powershell Set key in System.Security.Cryptography.HMACSHA512 - powershell

I have the code below:
# Powershell HMAC SHA 256
$message = 'Message'
$secret = 'secret'
$hmacsha = New-Object System.Security.Cryptography.HMACSHA512
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
$signature = [Convert]::ToBase64String($signature)
echo $signature
# Do we get the expected signature?
echo ($signature -eq 'z12KOCXYQjCZyKf6WP+yYBONCS+IwNuv9oPbRcL4u+WetE4BvAm1Ysy+bEyGxq/QDLAufO0sPnVLUl/ubvPGdQ==')
When i run this code on my computer, it works fine.
My issue is when i try to run it in my Azure environment. Azure don't like the syntax "$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)"
This is the error im getting when i try to publish the code:
An error occured while publishing the runbook 'HiBob'. Error details:
BadRequest: The Runbook definition is invalid. This type of assignment
is not supported. Only variable names (i.e.: $variable) may be used as
the target of an assignment statement..
basically I cant set this array column "key" using the " $hmacsha.key = "
method.
Anyone has a different idea to do this?
Thanks!

Related

Remove-MgApplicationKey - delete expired app registration certificates

I am updating my current scripts from the AzureAD module and want to update a script which deletes expired app registration certificates.
I can remove expired secrets using the new module, however the new command Remove-MgApplicationKey requires proof as per Microsoft document: https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.applications/remove-mgapplicationkey?view=graph-powershell-1.0. (As part of the request validation for this method, a proof of possession of an existing key is verified before the action can be performed).
`$params = #{
KeyId = "f0b0b335-1d71-4883-8f98-567911bfdca6"
Proof = "eyJ0eXAiOiJ..."
}
Remove-MgApplicationKey -ApplicationId $applicationId -BodyParameter $params`
Any suggestions on how to code this in PowerShell?
Thanks.
C# example from Microsoft doc: https://learn.microsoft.com/en-us/graph/application-rollkey-prooftoken
Code would look something like this
using assembly System;
using assembly System.Security.Cryptography.X509Certificates;
# Configure the following
$pfxFilePath = "<Path to your certificate file";
$password = "<Certificate password>";
$objectId = "<id of the application or servicePrincipal object>";
# Get signing certificate
#$signingCert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new([string]$pfxFilePath, [string]$password);
#$signingCert = [System.Security.Cryptography.X509Certificates]::X509Certificate2($pfxFilePath, $password);
$signingCert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new();
$signingCert.CreateFromEncryptedPemFile($pfxFilePath, $password, $null)
#$signingCert | Format-Table
#$signingCert.filename = $pfxFilePath;
#$signingCert.password = $password;
# audience
$aud = "00000002-0000-0000-c000-000000000000";
#aud and iss are the only required claims.
$claims = [System.Collections.Generic.Dictionary[string, object]]::new()
$claims.Add("aud", $aud)
$claims.Add("iss", $objectId)
#token validity should not be more than 10 minutes
$now = [DateTime]::UtcNow;
$securityTokenDescriptor = New-Object [System.Security.Cryptography.X509Certificates.SecurityTokenDescriptor]::new()
$securityTokenDescriptor.Claims = $claims,
$securityTokenDescriptor.NotBefore = $now,
$securityTokenDescriptor.Expires = $now.AddMinutes(10),
$securityTokenDescriptor.SigningCredentials = New-Object X509SigningCredentials($signingCert);
$handler = [Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler]::new();
$x = handler.CreateToken($securityTokenDescriptor);
Write-Host x;

PowerShell connect & append data to GoogleSheet

**Problem I am trying to solve: **
We want to be notified whenever one of our kiosk machines restart due to a Windows Update, so we can remotely connect right away and reset them to the desired state.
After trying different options (i.e. send email via SMTP triggered by an event via Task Scheduler, which proved unreliable due to script taking too long before restart occurs), this is the next attempted solution (perhaps it occurs faster?).
**Current solution attempted: **
Write data to a GoogleSheet via PowerShell script (below), triggered via Task Scheduler when a specific event occurs (i.e. Event Id: 1074). From there, GoogleSheet can easily send us the notification we want using Apps Script (details not relevant for this post).
Import-Module UMN-Google
# Set security protocol to TLS 1.2 to avoid TLS errors
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Google API Authozation
$scope = "https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.file"
$certPath = "C:/Scripts/GoogleService/my-cert-path.p12"
$iss = 'name#projectname.iam.gserviceaccount.com'
$certPswd = 'mypassword'
try {
$accessToken = Get-GOAuthTokenService -scope $scope -certPath $certPath -certPswd $certPswd -iss $iss
} catch {
$err = $_.Exception
$err | Select-Object -Property *
"Response: "
$err.Response
}
$accessToken
# Define the GoogleSheet and the target Sheet
$spreadSheetID = 'google-sheet-id-i-omitted-from-this-sample'
$sheetName = 'MachineActivityData'
$EventId = 1074
$A = Get-WinEvent -MaxEvents 1 -FilterHashTable #{Logname = "System" ; ID = $EventId }
$Message = $A.Message
$EventID = $A.Id
$MachineName = $A.MachineName
$Source = $A.ProviderName
# Set the arrayValues
$arrayValues = #($MachineName, $Source, $EventId)
$appendValue = 'Append'
# Write to GoogleSheet (appending data)
Set-GSheetData -accessToken $accessToken -append $appendValue -sheetName $sheetName -spreadSheetID $spreadSheetID -values $arrayValues
Issue encontered:
When running the above script, I get the following error:
Set-GSheetData : A positional parameter cannot be found that accepts argument 'Append'.
At C:\Scripts\script_GoogleSheetConnection.ps1:40 char:1
+ Set-GSheetData -accessToken $accessToken -append $appendValue -sheetN ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Set-GSheetData], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Set-GSheetData
As you can see, I am using UMN-Google. This documentation helps, but I couldn't find much more than this to help with this error.
This error has something to do with the -append value not being correct.
Per the linked documentation, it appears to be a string (as in the example, and function definition). But I tried other options as well (i.e. bool...).
Any idea why the function Set-GSheetData is not accepting this parameter?
Quick note, I am fairly new to using PowerShell. I appreciate any suggestions.
Thank you kindly,
I tried the above script, and expected data to be appended to the specified GoogleSheet. However, the function Set-GSheetData returned an error, as a parameter is invalid. Per documentation, the parameter I entered is correct.

powershell FTPS csv file [duplicate]

The problem:
A client requires that we upload extracted data from our system to their box.com platform, rather than our normal SFTP utility. I have box.com credentials, and am aware they require FTPS not SFTP, and require passive mode. I've cribbed a fragment from ThomasMaurer's Powershell FTP Upload and Download script. Powershell version on my server is 4.0
Code fragment is:
#config
$Username = "username#host.com"
$Password = "redactedpassword"
$LocalFile = "C:\path\to\my\file.csv"
$RemoteFile = "ftp://ftp.box.com:990/file.csv"
#Create FTPWebRequest
$FTPRequest = [System.Net.FtpWebRequest]::Create($RemoteFile)
$FTPRequest = [System.Net.FtpWebRequest]$FTPRequest
$FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$FTPRequest.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)
$FTPRequest.UseBinary = $true
$FTPRequest.UsePassive = $true
#read file for upload
$FileContent = gc -en byte $LocalFile
$FTPRequest.ContentLength = $FileContent.Length
#get stream request by bytes
$run = $FTPRequest.GetRequestStream()
$run.Write($FileContent,0,$FileContent.Length)
#cleanup
$run.Close()
$run.Dispose()
The error(s):
Exception calling "GetRequestStream" with "0" argument(s): "System error." At C:\path\to\my\powershellscript.ps1:28 char:1
+ $Run = $FTPRequest.GetRequestStream()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: () [], MethodInvocationException
+ FullyQualifiedErrorId: WebException
I also get downstream errors on calling the $FileContent.Length property and $run.close and $run.dispose().
Has anyone successfully automated to box (specifically) or to a passive implicit-ssl using only PowerShell 4.0 commands, and do you have a solid pattern I could reuse? Many thanks
I'm uploading files with a derived version of System.Net.WebClient, which supports FTP over TLS. This can easily be achieved by embedding C# code in PowerShell:
$typeDefinition = #"
using System;
using System.Net;
public class FtpClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
FtpWebRequest ftpWebRequest = base.GetWebRequest(address) as FtpWebRequest;
ftpWebRequest.EnableSsl = true;
return ftpWebRequest;
}
}
"#
Add-Type -TypeDefinition $typeDefinition
$ftpClient = New-Object FtpClient
$ftpClient.UploadFile("ftp://your-ftp-server/yourfile.name", "STOR", "C:\YourLocalFile.name")
The answer by #h0r41i0 solves the problem by using WebClient. But as the WebClient internally uses (Ftp)WebRequest, it cannot be the solution on its own.
I'll assume that the "System error" occurs because either OP is trying to connect to a secure port (990) with an insecure connection.
Or because the file is too large and the OP code tries to read it whole to memory:
$FileContent = gc -en byte $LocalFile
In either case, there's no reason to give up on FtpWebRequest. Just use a secure connection (FtpWebRequest.EnableSsl). And an efficient way to feed the data from the file to the FTP stream, for example Stream.CopyTo:
$request = [Net.WebRequest]::Create("ftp://ftp.example.com/remote/path/file.zip")
$request.Credentials = New-Object System.Net.NetworkCredential("username", "password")
$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$request.EnableSsl = $True
$fileStream = [System.IO.File]::OpenRead("C:\local\path\file.zip")
$ftpStream = $request.GetRequestStream()
$fileStream.CopyTo($ftpStream)
$ftpStream.Dispose()
$fileStream.Dispose()
For other options, see Upload files with FTP using PowerShell.
Though note that .NET framework does not support implicit TLS (what is typical use of 990). Only explicit TLS. But support for the explicit TLS is more common ayway. See Does .NET FtpWebRequest Support both Implicit (FTPS) and explicit (FTPES)?
Probably too late to be useful to original questioner, but I found this other answer did the trick for me: Cyril Gupta's answer to Upload files with ftp using powershell
Here is my revised edition, including URL encoding (since the box.com usernames are email addresses which include the "at sign"):
## https://stackoverflow.com/a/2485696/537243
## User comment complains can't turn off passive mode,
## but that is exactly what we want here!
[Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null
# config
$Username = "foo#bar.com"
$Password = "s3cr3tpAssw0rd"
$Servername = "ftp.box.com"
# This is what we need URI it to look like:
# ftp://foo%40bar.com:s3cr3tpAssw0rd#ftp.box.com/
$baseURI = "ftp://$([System.Web.HttpUtility]::UrlEncode($Username)):$([System.Web.HttpUtility]::UrlEncode($Password))#$($Servername)"
$LocalFile = "C:\tmp\to_upload\data.csv"
$RemoteFile = "date.csv"
$ftpURI = "$($baseURI)/$($RemoteFile)"
Write-output "ftp uri: $($ftpURI)";
$webclient = New-Object -TypeName System.Net.WebClient;
$ftpURI = New-Object -TypeName System.Uri -ArgumentList $ftpURI; #"convert" it
$webclient.UploadFile($ftpURI, $LocalFile);
Write-output "Uploaded $($LocalFile) ... "; # of course since we didn't use try/catch or other error dectection this is a bit presuming.
Also should note this example uses plain FTP, not FTPS or SFTP.

Encoding AWS Affiliate API String with PS gives wrong hash

From the following guide in AWS I need to generate an HMAC SHA256 Signature:
http://docs.aws.amazon.com/AWSECommerceService/latest/DG/rest-signature.html
My code is as follows:
$message = 'GET
webservices.amazon.com
/onca/xml
AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&AssociateTag=mytag-20&ItemId=0679722769&Operation=ItemLookup&ResponseGroup=Images%2CItemAttributes%2COffers%2CReviews&Service=AWSECommerceService&Timestamp=2014-08-18T12%3A00%3A00Z&Version=2013-08-01'
$secret = '1234567890'
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
$signature = [Convert]::ToBase64String($signature)
echo $signature
# Do we get the expected signature?
echo ($signature -eq 'j7bZM0LXZ9eXeZruTqWm2DIvDYVUU3wxPPpp+iXxzQc=')
Unfortunately I do not get the same hash as AWS does in it's example. What did I miss?
I got it eventually.
It had something to do with the line breaks:
$message = "GET`nwebservices.amazon.com`n/onca/xml`nAWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&AssociateTag=mytag-20&ItemId=0679722769&Operation=ItemLookup&ResponseGroup=Images%2CItemAttributes%2COffers%2CReviews&Service=AWSECommerceService&Timestamp=2014-08-18T12%3A00%3A00Z&Version=2013-08-01"

Attempting to see if my public IP has changed automatically with PowerShell

I'm trying to write a script that checks my current public IP address to one that I've written in to see if it has changed. So far I've got this:
$NIP = "97.121.63.227"
$url = "http://checkip.dyndns.com"
$webclient = New-Object System.Net.WebClient
$Ip = $webclient.DownloadString($url)
$Ip2 = $Ip.ToString()
$ip3 = $Ip2.Split(" ")
$ip4 = $ip3[5]
$ip5 = $ip4.replace("</body>","")
$FinalIPAddress = $ip5.replace("</html>","")
$Prod = $NIP.CompareTo($FinalIPAddress)
$Prod
Whenever I run it though, comes up
Missing property name after reference operator.
At line:1 char:17
Pretty new to PowerShell and have no idea what I'm doing wrong
maybe you could use a regex to avoid multiple split and replace :
$NIP = "97.121.63.227"
$url = "http://checkip.dyndns.com"
$webclient = New-Object System.Net.WebClient
$Ip = $webclient.DownloadString($url)
$FinalIPAddress=[regex]::match($ip,"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b").Value
$NIP -eq $FinalIPAddress
I was not able to reproduce the error unfortunately. Perhaps set a breakpoint (F9) at the top line and step through (F10) the script to narrow in on the cause. The error message is pointing to line 1...did you include that line in your example?