I'm trying to call a WCF service from PowerShell.
This is what I have so far based on a few misc example I found on the web:
# Create the WebSvcURL variable and pass the WSDL URL
$WebSvcURL= “http://localhost/DEMO/SetPassKey/SetPassKey_Logic_SetPassKeyWebService_SetPassKeyWCF.svc?wsdl“
#Create the Web Service Proxy Object
#$serviceProxy = New-WebServiceProxy -Uri $WebSvcURL -Namespace "http://Sample.SetPassKey.Logic" -Class Program -UseDefaultCredential
$serviceProxy = New-WebServiceProxy -Uri $WebSvcURL -UseDefaultCredential
# Create Request Object
$namespace = $serviceProxy.getType().namespace
write-host "Namespace=$namespace"
$req = New-Object ($namespace + "/SetPassKeyOrchWebRequest")
$resp = New-Object ($namespace + "/SetPassKeyOrchWebResponse")
$req.NewPassKey = "TEST" # <--- PUT YOUR NEW PASSWORD HERE
$resp = $serviceProxy.SetPassKey($req)
$resp
I'm confused on a few things:
If and when I need to include the -Namespace and -Class parameters on the. Since it looks at the WSDL, I don't understand why it needs the -Namespace and -Class.
How to construct the request/response objects
Should the URL be the actual URL of the web service or should it include the ?wsdl suffix
UPDATE:
I found this blog which states:
The -Namespace parameter is optional and when not
specified then it gets a random value from the cmdlet.
I was thinking it was an XML Namespace, but it's a .NET framework namespace.
# Create the WebSvcURL variable and pass the WSDL URL
$WebSvcURL= “http://localhost/DEMO/SetPassKey/SetPassKey_Logic_SetPassKeyWebService_SetPassKeyWCF.svc?wsdl“
#Create the Web Service Proxy Object
$serviceProxy = New-WebServiceProxy -Uri $WebSvcURL -UseDefaultCredential -Namespace "MyNamespace" -Class Program
# Create Request Object
$req = New-Object ("MyNamespace.SetPassKeyOrchWebRequest")
$resp = New-Object ("MyNamespace.SetPassKeyOrchWebResponse")
$req.NewPassKey = "TEST" # <--- PUT YOUR NEW PASSWORD HERE
$resp = $serviceProxy.SetPassKey($req)
$resp
Now I get this error:
Exception calling "SetPassKey" with "1" argument(s): "The underlying connection was closed: An unexpected error occurred on a
receive."
The webservice can be called by a C# console program, so I know it works. Just need to call it from PowerShell.
I tried some things, and finally got it to work.
I did change my binding from WCF-WSHttp to WCF-BasicHttp.
I also followed this post, which said they only got it working by using the auto-generated namespace.
One of my issues originally was using "/" instead of "." as the separator between the namespace and the web request/response class names.
I'm still confused by the -namespace and -class parameters, as the post above said it only got the process working by using the autogenerated namespace (which happens when you omit the -namespace parm).
My code ended up something like this:
# Create the WebSvcURL variable and pass the WSDL URL
$WebSvcURL= “http://localhost/DEMO/SetPassKey/SetPassKey_Logic_SetPassKeyWebService_SetPassKeyWCF.svc?wsdl“
#Create the Web Service Proxy Object
$serviceProxy = New-WebServiceProxy -Uri $WebSvcURL -UseDefaultCredential
$autoGenNamespace = $serviceProxy.getType().namespace
write-host "Namespace=$namespace"
$req = New-Object ($autoGenNamespace + ".SetPassKeyOrchWebRequest")
$resp = New-Object ($autoGenNamespace + ".SetPassKeyOrchWebResponse")
$req.NewPassKey = "TEST" # <--- PUT YOUR NEW PASSWORD HERE
$req.NewPassKey = "TEST" # <--- PUT YOUR NEW PASSWORD HERE
Write-Host "Request:"
Write-Host ($req | Format-Table | Out-String)
Write-Host "About to call WebService"
$resp = $serviceProxy.SetPassKey($req)
Write-Host "Response:"
Write-Host ($resp | Format-Table | Out-String)
NOTE: Just putting the variable name without the write-host statement was causing things to come out in a different sequence. The FormatTable was still truncating some fields, so I will list each return string in my $resp separately.
Related
I am trying to access an application via API REST but I am stuck in the process using ADF.
Basically this process consists in 2 steps.
1 - Getting a session (https://horizon.akixi.com/CCS/API/v1/session)
2 - Authenticating (https://horizon.akixi.com/CCS/API/v1/login?locale=en_GB") using Username and Password.
I have created a Linked Service (Rest) and set the Base URL as (https://horizon.akixi.com/CCS/API/v1/session)
Authentication Anonymous.
Then I create a Data Set to point this API and finally I create a "Copy Data" and tried to set on the Additional Header the authentication's details, but it is not working, I got an error 405.
Basically I can run the below script using Powershell and it is working as expected, but is required to use it on ADF instead.
The script in Powershell is this one.
$user = "xxxxxx#mail.com"
$pass = "123456789"
$secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$pass)))
#Get Session
$url = "https://horizon.akixi.com/CCS/API/v1/session"
$response = Invoke-RestMethod -uri $url -Method Post -SessionVariable se
#Authentication
Write-Host "Authenticating" -ForegroundColor Green
$headers = #{
'Authorization' = "Basic $base64AuthInfo"
}
$headers
$url = "https://horizon.akixi.com/CCS/API/v1/login?locale=en_GB"
$response = Invoke-RestMethod -uri $url -Headers $headers -Method Get -WebSession $se
#List Reports
$url = "https://horizon.akixi.com/CCS/API/v1/report"
$response = Invoke-RestMethod -uri $url -Method Get -WebSession $se
$response
Thank you all.
As the 3 steps are separate, and only the last one fetches data, you should break up the process into multiple activities.
Use Web Activity for the first two steps,
https://horizon.akixi.com/CCS/API/v1/session
https://horizon.akixi.com/CCS/API/v1/login?locale=en_GB"
extract the session variable or Authentication from the web activities. Pass it to the copy activity. The copy activity should target
https://horizon.akixi.com/CCS/API/v1/report
I have a situation where in the Azure automation runbook results in 'Completed' state and does not run the 'actual' code. I have pasted the code below. It creates a Event Hub inside a Namespace. The code works perfectly executing in local machine but it does not execute in Runbook.
I have written a 'write-output "Declaring local variables for use in script"' --> to check if the printing is working. However, the code is not going beyond that. I am sure, I am missing some thing. Kindly help me.
Param(
[Parameter(Mandatory=$true)]
[string] $NameSpaceNameName,
[Parameter(Mandatory=$true)]
[string[]] $EventhubNames,
[Parameter(Mandatory=$true)]
[string] $ProjectId,
[Parameter(Mandatory=$true)]
[int] $PartitionCount,
[Parameter(Mandatory=$true)]
[string]$Requested_for,
[Parameter(Mandatory=$true)]
[string]$Comments
)
## Login to Azure using RunAsAccount
$servicePrincipalConnection = Get-AutomationConnection -Name 'AzureRunAsConnection'
Write-Output ("Logging in to Az Account...")
Login-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
write-output "Declaring local variables for use in script"
## Declaring local variables for use in script
$Creation_date = [System.Collections.ArrayList]#()
$ResourceGroups = Get-AzResourceGroup
$provided_name_space_exists = $false
## Change context to Platform subscription
select-azsubscription -subscription "GC302_Sub-platform_Dev"
## Create Event Hub
foreach($Resourcegroup in $ResourceGroups){
Write-Host("Processing the Resource Group: {0} " -f $Resourcegroup.ResourceGroupName)
$EventhubNameSpaces = Get-AzEventHubNamespace -ResourceGroupName $ResourceGroup.ResourceGroupName
# Iterate over each Namespace. Fetch the Resource Group that contains the provided Namespace
foreach($EHNameSpace in $EventhubNameSpaces){
if($EHNameSpace.Name -eq $NameSpaceName){
$provided_name_space_exists = $true
Write-Host ("Found the provided Namespace in resource group: {0}" -f $Resourcegroup.ResourceGroupName)
Write-Output ("Found the provided Namespace in resource group: {0}" -f $Resourcegroup.ResourceGroupName)
$nameSpace_resource_group = $ResourceGroup.ResourceGroupName
# Fetch the existing Event Hubs in the Namespace
$existing_event_hubs_list = Get-AzEventHub -Namespace $EHNameSpace.Name -ResourceGroupName $nameSpace_resource_group
## Check provided EH for uniqueness
if($existing_event_hubs_list.Count -le 1000){
for($i = 0;$i -lt $EventhubNames.Count;$i++){
if($existing_event_hubs_list.name -notcontains $EventhubNames[$i]){
$EventHub = New-AzEventHub -ResourceGroupName $nameSpace_resource_group -Namespace $EHNameSpace.Name -Name $EventhubNames[$i] -PartitionCount $PartitionCount
$date = $EventHub.CreatedAt
$Creation_date+= $date.GetDateTimeFormats()[46]
}else{
Write-Host ("Event hub: '{0}' already exists in the NameSpace: {1}. skipping this Event hub creation" -f $EventhubNames[$i], $EHNameSpace.Name)
}
}
}else{
Write-Host ("The Namespace - {0} has Event Hubs count greater or equal to 1000." -f $EHNameSpace.Name)
Write-Host ("Please refer the Link for Eevent Hubs quota/limit: 'https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-quotas#event-hubs-dedicated---quotas-and-limits'")
exit
}
}
}
}
# Print a message that Namespace does not exist
if($provided_name_space_exists -eq $false){
Write-Host ("Provided NameSpace: {0} does not exist." -f $NameSpaceName)
exit
}
Screenshot:
You have $NameSpaceNameName in the parameters section of the runbook but later in the runbook at 50th line you have $NameSpaceName which is not the same as mentioned in parameters section. Correct it and then it should work as expected. One suggestion is to always have an else block wherever you have if block to overcome such issues in future.
Following a script (from here) that many others have suggested works OK, I am having an error that is just outside my ability to understand. I am novice-to-intermediate with Power Shell and just beginning with API's.
The script is:
$domain = 'example.com' # your domain
$name = 'xyz' # name of the A record to update
$key = 'myKey # key for godaddy developer API
$secret = 'mySecret' # Secret for godday developer API
$headers = #{}
$headers["Authorization"] = 'sso-key ' + $key + ':' + $secret
$result = Invoke-WebRequest https://api.godaddy.com/v1/domains/$domain/records/A/$name -method get -headers $headers
$content = ConvertFrom-Json $result.content
$dnsIp = $content.data
# Get public ip address
$currentIp = Invoke-RestMethod http://ipinfo.io/json | Select -exp ip
# THE CODE WORKS FINE UP TO HERE
if ( $currentIp -ne $dnsIp) {
$Request = #{ttl=3600;data=$currentIp }
$JSON = Convertto-Json $request
# THE FOLLOWING LINE FAILS WITH THE ERROR NOTED BELOW
Invoke-WebRequest https://api.godaddy.com/v1/domains/$domain/records/A/$name -method put -headers $headers -Body $json -ContentType "application/json"
}
The following error is returned for the final Invoke-WebRequest:
Invoke-WebRequest : {"code":"INVALID_BODY","fields":[{"code":"UNEXPECTED_TYPE","message":"is not a array","path":"records"}],"message":"Request body doesn't fulfill schema, see details in `fields`"}
At C:\tfsCode\tfs\api.ps1:25 char:5
+ Invoke-WebRequest https://api.godaddy.com/v1/domains/$domain/reco ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
The Go Daddy reference page for the Get API is here and for the Put API is here.
The PUT API documentation says it’s expecting the body to be an array. This is also what the error message is saying. Try changing this line:
$Request = #{ttl=3600;data=$currentIp }
to
$Request = #(#{ttl=3600;data=$currentIp })
#() creates an array in PowerShell, when converted to JSON it will still be an array
#{} creates a hashtable in PowerShell, when converted to JSON it will be an object
I'm relatively new to Powershell so really not sure where to go with this issue now. I am trying to download a file from a subversion repository and am getting the (401) Unauthorized" error. I am able to log into the site and download the file using IE using the exact Same credentials on the same machine.
$source = "http://repository/folder/File.exe"
$destination = "E:\Temp\File.exe"
$wc = New-Object System.Net.WebClient
$user="user"
$pwd=convertto-securestring -string "password" -AsPlainText -force
$creds=New-Object System.Management.Automation.PSCredential -ArgumentList $user, $pwd
$wc.Credentials = New-Object System.Net.NetworkCredential ($user, $Creds.GetNetworkCredential().Password,"DOMAIN")
$download=$wc.DownloadFile($source, "$destination")
Exception calling "DownloadFile" with "2" argument(s): "The remote server returned an error: (401) Unauthorized."
Any ideas if this is cross platform issue? And how to get around this?
Thanks
Are you using basic auth on your iis/apache? If so try this:
$source = "http://repository/folder/File.exe"
$destination = "E:\Temp\File.exe"
$wc = new-object System.Net.WebClient
$credCache = new-object System.Net.CredentialCache
$creds = new-object System.Net.NetworkCredential($user,$pwd)
$credCache.Add($source, "Basic", $creds)
$wc.Credentials = $credCache
$wc.DownloadFile($source, $destination)
NOTE: I cannot use PowerShell V3.0 here otherwise I'd be using Invoke-WebRequest and living a happy life.
I have a PowerShell V2.0 script that needs to POST data to a HTTP-Basic authenticated resource. For the purposes of the script I don't want or need to know the user's password, I just want to convert from a PSCredentials object (as returned from PromptForCredential) to a NetworkCredential for use with HttpWebRequest.
$uri = "https://example.com/some/resource/"
# Get our user's credentials...
$defaultUsername = "Some Username"
$caption = "Authentication required"
$message = "A username and password is required for ${uri}"
#$target = $uri #<<--NOTE: This prepends $uri+"\" to the username.
#$target = "" #<<--NOTE: This prepends "\" to the username.
$target = $null #<<--NOTE: This still prepends "\" to the username.
$psCredential = $Host.UI.PromptForCredential($caption, $message, $defaultUsername, $target)
# Construct a CredentialCache for HttpWebRequest...
# NOTE: We need to delete the "domain part" of the username from the PSCrential.Username, otherwise we get "Something\Username"
$username = ($psCredential.Username).Split('\')[1]
$networkCredential = New-Object System.Net.NetworkCredential($username, [System.Security.SecureString]$psCredential.Password)
$credentialCache = New-Object System.Net.CredentialCache
$credentialCache.Add( (New-Object Uri($uri)), "Basic", $networkCredential)
#...
$request = New-Object System.Net.HttpWebRequest($uri)
$request.Credentials = $credentialCache
#...
[System.Net.HttpWebResponse]$response = [System.Net.HttpWebResponse]$request.GetResponse()
This of course fails with the exception:
Exception calling "GetResponse" with "0" argument(s):
"The remote server returned an error: (401) Unauthorized."
Allegedly we have a NetworkCredential(String userName, SecureString password) constructor, but the user's credentials arrive the server as username:System.Security.SecureString.
Is there some little detail I'm missing? Do I need to decrypt the SecureString and pass that to the NetworkCredential(String userName, String password) constructor instead?
I've found the problem... the NetworkCredential(String userName, SecureString password) constructor is only available starting from .NET Framework 4.0. Of course PowerShell 2.0 is running in .NET 2.0.
While there are ways and means of making PowerShell 2.0 run inside .NET 4.0 I'm not a liberty to alter the runtime environment's configuration.
Instead I've gone down the "Unsecure String" path. Based on the article "How to properly convert SecureString to String" I've created this PowerShell function:
function Convert-To-Unsecure-String {
Param(
[Parameter(HelpMessage="The SecureString object to make a very unsecure String")]
[ValidateNotNull()]
[System.Security.SecureString]
$securePassword
)
$unmanagedString = [System.IntPtr]::Zero
try {
$unmanagedString = [Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($securePassword);
return [Runtime.InteropServices.Marshal]::PtrToStringUni($unmanagedString);
}
finally {
[Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($unmanagedString);
}
}
And replace the original example's NetworkCredential constructor with:
$networkCredential = New-Object System.Net.NetworkCredential($username, (Convert-To-Unsecure-String($psCredential.Password)) )
Now I'm getting the correct base64 encoded "username:password" string at the server.
I ran into the same issue. The fix for mine was very simple. Do not include the Domain name in the user name. I was trying to connect to JIRA to run a JQL.
Don't do this
$userName = Me#Mydomain; Or $userName=MyDomain/Me
But do that
$userName = Me