PowerShell question - webrequest or curl doesn't work with tasks - windows

I've written (partly by myself) a script which get the ip address with a webrequest and save it as variable for a dyndns update. If I start the script via ISE or directly with PowerShell it works as expected. But if I start it via scheduled task the web request, whether with invoke-webrequest or curl doesn't works. The script will be started but the variable is empty. If I try to save the output of the command to a file its also empty, so I don't know why it doesn't work.
Here is the script:
# Get IPv4 and IPv6 from wtfismyip.com
$strIPv6 = Invoke-WebRequest -uri http://[2a01:4f9:4b:4c8f::2]/text | select Content -ExpandProperty Content
$strIPv4 = Invoke-WebRequest -uri http://95.217.228.176/text | select Content -ExpandProperty Content
$strIPs = $strIPv4 + "," + $strIPv6
$strIPs = [string]::join("",($strIPs.Split("`n")))
echo "IPs" >> C:\temp\test.txt
echo $strIPs >> C:\temp\test.txt
$strDYNDNS_URL = "https://dyndns.strato.com/nic/update?hostname=sub.domain.de&myip=$strIPs"
# Debug Informations
write "IPv4: $strIPv4"
write "IPv6: $strIPv6"
write "Strato URL: $strDYNDNS_URL"
# Strato DynDNS Update
$user = "domainuser"
$pass = "pass"
$pair = "${user}:${pass}"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$headers = #{ Authorization = $basicAuthValue }
Invoke-WebRequest -uri $strDYNDNS_URL -Headers $headers
The scheduled task runs for testing with an admin user with the following settings:
Start with highest privileges
Trigger: every hour
Cmd: powershell.exe ExecutionPolicy Bypass -Command "C:\Daten\Scripte\StratoDynDNS-Update.ps1"
Does have anyone an idea why it doesn't work? Or is there a better solution?
The goal is to make a dns update at strato because the ISP of my client doesn't provide static ips, even with a business internet connection.

Related

TF history - prompt user

I want to prompt only username/author of last changeset. It is possible?
tf history . /r /noprompt /stopafter:1
I don't think we can prompt only the username/author of the latest changeset by running the History command. Basically, the command will list the Changeset, User,Dateand Comment. See History command for details.
However you can try to write a script to run the command and retrieve the Author only if possible.
Besides, you can also achieve that by calling the Get Changesets REST API in a script.
Below PowerShell script for your reference:
$collectionurl = "https://xxx/DefaultCollection"
$project = "ProjectName"
$user = ""
$token = "PAT"
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$changeseturl = "$collectionurl/_apis/tfvc/changesets?searchCriteria.itemPath=$/$project&api-version=6.0"
$result = (Invoke-RestMethod -Uri $changeseturl -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}).value | Select -first 1
Write-host "The last changeset author is:" $result.author.displayName

How to download artifacts from CircleCI via Powershell command Invoke-RESTMethod

I'm trying to get artifacts from CircleCI in Powershell and getting back an unfamiliar data format?
Powershell likes to auto-convert your API’s JSON response to a PSCustomObject. This normally would be what I want.
Here is an example of my attempts at getting clean data.
Add the necessary .NET assembly
Add-Type -AssemblyName System.Net.Http
Create the HttpClient object
$client = New-Object -TypeName System.Net.Http.Httpclient
Get the web content.
$task = $client.GetByteArrayAsync(“https://circleci.com/api/v1.1/project/$vcs_type/$username/$project/$build_number/artifacts?circle-token=$CIRCLE_TOKEN”)
Wait for the async call to finish
$task.wait();
results:
(({
:path “src./file1.txt”,
:pretty-path “src/file1.txt”,
:node-index 0,
:url “https://15-198716507-gh.circle-artifacts.com/0/src/file1.txt”
} {
:path “src/file2.txt”,
:pretty-path “src/file2.txt”,
:node-index 0,
:url “https://15-198716507-gh.circle-artifacts.com/0/src/file2.txt”
}…continued
As you can see this is not JSON or YAML. Let’s try the built-in PowerShell tools like Invoke-RestMethod.
Invoke-RESTMethod -uri https://circleci.com/api/v1.1/project/$vcs_type/$username/$project/$build_number/artifacts?circle-token=$CIRCLE_TOKEN -Method GET
**Output:**
({
:path “src/file1.txt”,
:pretty-path “src/file1.txt”,
:node-index 0,
:url “https://15-198716507-gh.circle-artifacts.com/0/src/file1.txt”
} {
:path “src/file2.txt”,
:pretty-path “src/file2.txt”,
:node-index 0,
:url “https://15-198716507-gh.circle-artifacts.com/0/src/file2.txt”
}…continued
Dang same output. I know from the Invoke-RestMethod documentation that PS sees JSON and auto converts it to a PS object. Maybe it's converting a data type I'm not familiar with? I found it odd that PowerShell was getting EDN type when every other attempt outside PowerShell was JSON.
Maybe they should have the API updated to reply to PS request with JSON by default.
What is wrong with PowerShell not getting JSON data?
It's EDN, didn't know this until CircleCI answered a question on this topic. So if you are using PowerShell to retrieve artifacts from CircleCI you definitely want to know this.
you need to pass a header specifying the data type returned.
(Accept: application/json)
A CircleCI Support member let me know that in PowerShell you have to specify an Accept header to receive the data in JSON. No wonder I'm getting weird output!
So trying again with the new accept JSON header we have this command below.
Working command to get data in JSON and have it auto-convert to a PSObject.
Invoke-RestMethod -Uri https://circleci.com/api/v1.1/project/$vcs_type/$username/$project/$build_number/artifacts?circle-token=$CIRCLE_TOKEN -Method GET -ContentType 'application/json' -UseBasicParsing -Header #{"Accept" = "application/json"}
OUTPUT
$response|select path,url
path
----
src.orig/file1.txt
src.orig/file2.txt
url
---
https://15-824975-gh.circle-artifacts.com/0/src.orig/file1.txt
https://15-824975-gh.circle-artifacts.com/0/src.orig/file2.txt
Using the PS commands Invoke-WebRequest/Invoke-RestMethod both will receive data in EDN format if you don't do the below. Yay now I can use the data as I see fit to download my artifacts.
Reply from CircleCI that got me the solution.
#burninmedia So what's being sent back is actually a data format called EDN. If you want to return JSON you'll need to pass a header specifying so (Accept: application/json). Thanks!
Here is a simple script I wrote to download all the artifacts. Please be sure you're setting the environment variables.
if ($USERNAME -eq $null) { write-host " please add required variable USERNAME" ;exit }
if ($VCS_TYPE -eq $null) { write-host " please add required variable VCS_TYPE" ;exit}
if ($CIRCLE_TOKEN -eq $null) { write-host " please add required variable CIRCLE_TOKEN" ;exit}
if ($BUILD_NUMBER -eq $null) { write-host " please add required variable BUILD_NUMBER" ;exit}
if ($PROJECT -eq $null) { write-host " please add required variable PROJECT" ;exit}
if ($BASEPATH -eq $null) { write-host " please add required variable BASEPATH" ;exit}
$response = Invoke-RestMethod -Uri https://circleci.com/api/v1.1/project/$VCS_TYPE/$USERNAME/$PROJECT/$BUILD_NUMBER/artifacts?circle-token=$CIRCLE_TOKEN -Method GET -ContentType 'application/json' -UseBasicParsing -Header #{"Accept" = "application/json"}
ForEach ($i in $response){
$PATH = $(Split-Path -Path "$($BASEPATH)\$($i.path)")
if (-Not ( Test-Path $PATH) ) {
write-host "Creating folder: $($PATH)"
New-Item -ItemType Directory -Force -Path "$($PATH)"
}
Write-Host "Saving artifact $($i.pretty_path) to file: $($BASEPATH)\$($i.path)"
Invoke-RestMethod "$($i.url)?circle-token=$($CIRCLE_TOKEN)" -UseBasicParsing -OutFile "$($BASEPATH)\$($i.path)"
}
Bash version
export CIRCLE_TOKEN=':your_token'
echo $(https://circleci.com/api/v1.1/project/$vcs-type/$username/$project/$build_number/artifacts?circle-token=$CIRCLE_TOKEN) > ./artifact_json
for ((i = 0 ; i <= $(jq -c '.[].url ' ./artifact_json|wc -l) ; i++));
do
path=$(jq -c ".[$i].path" ./artifact_json|tr -d '"');
url=$(jq -c ".[$i].url" ./artifact_json|tr -d '"');
pathdir=$(dirname "$path")
echo "URL: $url"
echo "path: $path"
echo "Pathdir: $pathdir"
[ -d $pathdir ] && mkdir -p "$pathdir" #check if folder exists if not mkdir
wget -o $path $url
done
rm ./artifact_json```

Improve performance in powershell file generation

I have written a basic script that gets system logs from a restful api, and writes it to a json file. It works, but im seeing huge RAM issues - i think its because the script is getting the whole payload of system log entries and storing it in memory before writing it to the file.
The do loop in the script below is for pagination - the api only returns a certain number of events at a time so it needs to be iterated through.
Can performance be improved here - I guess can the payload in memory get written to a file when it hits a certain size, and then it just loops over? Or is there anything else that can be done to reduce the system resources?
Thanks for your help!
#Name: getLogs.ps1
#Purpose: Script for exporting logs to a json file
#variables
$org = "<api url here>"
$token="<api token here>"
$filePath = "D:\Downloads\logs\test2.json"
#format the date and append 00:00:00
$fromTime = Get-Date -Format s
$fromTime = $fromTime.Substring(0,10) + "00%3A00%3A00Z"
#format the date and append 23:59.59
$toTime = Get-Date -Format s
$toTime = $fromTime.Substring(0,10) + "T23%3A59%3A59Z"
### Set $uri as the API URI for use in the loop
$uri = "$org/api/v1/logs?until=$toTime&limit=20&sortOrder=DESCENDING&q=&since=$fromTimeT00"
### Define $allLogsas empty array
$allLogs = #()
### Use a while loop and get all users from Okta API
DO
{
$webrequest = Invoke-WebRequest -Headers #{"Authorization" = "SSWS $token"} -Method Get -Uri $uri
$link = $webrequest.Headers.Link.Split("<").Split(">")
$uri = $link[3]
$json = $webrequest | ConvertFrom-Json
$allLogs += $json
#slow it down to avoid rate limits
Start-Sleep -m 1001
} while ($webrequest.Headers.Link.EndsWith('rel="next"'))
# get results, switch to json, save
$allLogs | ConvertTo-Json | Out-File $filePath
You could try changing:
$json = $webrequest | ConvertFrom-Json
To:
$webrequest | Out-File $filePath -Append
And then doing away with $alllogs entirely.
There is another post about performance and using the PoSH Invoke-* cmdlets.
As noted in the previous post, there are just slow in general prior to PoSHv6.
See this post for a that on the topic.
Choppy File Download using Powershell on Azure VM

PostgreSQL and schedule Windows 2012 R2 Schedule

I have a question, last saturday when I was migrate DC from Windows 2003 to 2012R2, everything was migrate ok, but I can't run a ps script on Windows 2012R2. I change some parameter, mail adress etc.
param([String]$EmailTo = "user#domain.com")
psql.exe -h 10.1.1.20 -p 5432 -w -H -f C:\Scripts\errors_o_htm_V3.sql' -o 'C:\Scripts\errors.html -U script database
$file = "C:\Scripts\errors.html"
$old = Get-Content $file
Add-Content -Path $file -Value $old
$EmailFrom = "sender#domain.com"
$Subject = "Reports"
$SMTPServer = "smtp.serwer.com"
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $false
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("user","password");
$msg = new-object Net.Mail.MailMessage
$msg.From = $EmailFrom
$msg.To.Add($EmailTo)
$msg.To.Add("user#domain.com")
$msg.Subject = $Subject
$msg.IsBodyHTML = $True
$msg.Body = $old
$msg.BodyEncoding = [System.Text.Encoding]::GetEncoding("UTF-8")
$SMTPClient.Send($msg)
When I run script manualy, he generate error file and send it, but when I want to set it in scheduler - he send an empty mail, something wrong with psql.exe -h ......
I add psql path to Environment Variables.
In scheduler i set:
Program/Script powershell.exe or full path
Add arguments C:\Scripts\script.ps1, and also I add -f before path.
But when I run this script he don't generate the error file with data.
I thing something is wrong with shedule parameters.

failed to join domain with automated powershell script -- "unable to update password"

I'm trying to add a host to the domain with a Powershell script. The script fails with the error below when it's called via CloudFormation or Ansible. It's succeed when I run it manually on the host.
I suspect I'm doing something wrong with users (I run as admin manually) so I've tried to force it to run as admin all the time. Unfortunately that didn't work either.
Has anyone seen this issue before?
Error:
> [DEBUG] Command 4-add-to-domain output: Add-Computer : Computer
> 'WIN-xxxxx' failed to join domain
>
> 'aws.cloud.bp.com' from its current workgroup 'WORKGROUP' with
> following error
>
> message: Unable to update the password. The value provided as the
> current
>
> password is incorrect.
>
> At line:1 char:1
>
> + Add-Computer -DomainName $domain -Credential $credential -OUPath $ouPath
>
> -Restar ...
>
> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> ~~~
>
> + CategoryInfo : OperationStopped: (WIN-K9DU7TO9331:String) [Add-
>
> Computer], InvalidOperationException
>
> + FullyQualifiedErrorId : FailToJoinDomainFromWorkgroup,Microsoft.PowerShe
>
> ll.Commands.AddComputerCommand
PS1:
if ((gwmi win32_computersystem).partofdomain -eq $true)
{
write-host "already in domain"
}
else
{
$domain = $domainname
$password = $password | ConvertTo-SecureString -asPlainText -Force
$username = $uid
$credential = New-Object System.Management.Automation.PSCredential($username,$password)
$ouPath = $oupath
$cmd = 'Add-Computer -DomainName $domain -Credential $credential -OUPath $ouPath -Restart'
$runas = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
$log = "not running as admin"
$log | out-file -Filepath $logger -append
} else {
$log = "running as admin, about to run $cmd"
$log | out-file -Filepath $logger -append
Invoke-Expression -Command $cmd
}
}
The answer was simpler than I thought: when the script's running via the automation tool (either CloudFormation or Ansible) it was running as local admin. However, manually it's running as domain\admin. therefore what I needed to do is call it with username $username = "mydomain\my-domain-user" rather than simply "my-domain-user".
Hope this will help for people hitting the same problem...
Taken from: http://www.gi-architects.co.uk/2017/01/powershell-add-computer-error-when-executed-remotely/
The root of the problem is (given that your password is correct) when running things interactively the domain is pre-appended and as such you only need to provide the user. But in a non-interactive environment, the domain is not known as such it’s a very simple fix, make sure you either include the short domain names like “contoso\DMAdmin” or the full FQDN “DMAdmin#contoso.com.
Have you tried the password without the ConvertTo-SecureString? Just to test it? I had some issues with that when I was trying to remotely change local admin passwords on my domain. From what I could gather, when you convert it to a secure string and then assign it as a variable, the actual password seems to get lost. Now, I'm a real newbie with powershell, but I could only get ConvertTo-SecureString to work when it was called directly, not as a variable though.
I'm not sure why it wold work when you run it manually, but that's what I would try first to try and isolate the issue. If I'm way off feel free to correct me.

Resources