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;
Related
I am using https://github.com/microsoftgraph/msgraph-sdk-powershell, as I need Powershell 7 support for my script, the AzureAD module has a ton of issues in anything but Powershell 5 on Windows I am finding. Basically, I am trying to create an app registration in a B2C tenant. The problem I was having, was my script seemed fine but I wasn't able to grant any admin consent to any of the scopes defined. Then I noticed the issue - when you create an app registration in the portal it automatically gets a service principal, which New-MgApplication does not do.
I have the below script which works, up until I try and assign the service principal to my app using New-MgServicePrincipalAppRoleAssignment, where it breaks down with the error: New-MgServicePrincipalAppRoleAssignment_CreateExpanded: Not a valid reference update.
I am unsure if this is the function appropriate for my need or whether New-MgRoleManagementDirectoryRoleAssignment is the correct function.
function Upsert-AppRegistration {
Param(
[string] $TemplateParametersFile,
[string] $ResourceGroupName
)
$templateParameters = Get-Content $TemplateParametersFile | ConvertFrom-Json
$customerName = $templateParameters.parameters.customerName.value
$deploymentIdentifier = $templateParameters.parameters.deploymentIdentifier.value
$b2cTenantId = $templateParameters.parameters.b2cTenantId.value
$b2cTenantName = $templateParameters.parameters.b2cTenantName.value
$GraphConnection = Connect-Graph -TenantId $b2cTenantId -Scopes "User.Read","User.ReadWrite.All","Mail.ReadWrite",`
"Directory.ReadWrite.All","Chat.ReadWrite", "People.Read", `
"Group.Read.All", "Directory.AccessAsUser.All", "Tasks.ReadWrite", `
"Sites.Manage.All"
[string[]]$webRedirectUris =
"https://localhost:5050/LoginView",
"https://localhost:5050/DashboardView",
"https://localhost:5050/UsersView",
"https://localhost:5050/OrdersView"
# Our custom app.login scope for delegated permissions from front-end login
$oauth2PermissionScopes = #{
"Id" = [guid]::NewGuid().guid
"Value" = "app.login"
"AdminConsentDescription" = "This will provide the application access to login"
"AdminConsentDisplayName" = "Admin delegated login"
"IsEnabled" = $true
"Type" = "Admin"
}
[object[]]$appLoginScope = #{
"Id" = $oauth2PermissionScopes.Id
"Type" = "Scope"
}
# Microsoft.Graph ResourceAccess scopes and roles
$mgOfflineAccessScope = #{
"Id" = "7427e0e9-2fba-42fe-b0c0-848c9e6a8182"
"Type" = "Scope"
}
$mgOpenidScope = #{
"Id" = "37f7f235-527c-4136-accd-4a02d197296e"
"Type" = "Scope"
}
$mgDirectoryReadWriteAllRole = #{
"Id" = "19dbc75e-c2e2-444c-a770-ec69d8559fc7"
"Type" = "Role"
}
$mgResourceAccess = $mgOfflineAccessScope, $mgOpenidScope, $mgDirectoryReadWriteAllRole
[object[]]$requiredResourceAccess = #{
"ResourceAppId" = "00000003-0000-0000-c000-000000000000"
"ResourceAccess" = $mgResourceAccess
}
$mgApplicationParams = #{
"DisplayName" = "${customerName}-${deploymentIdentifier}"
"ApiOauth2PermissionScopes" = $oauth2PermissionScopes
"ApiRequestedAccessTokenVersion" = 2
"ImplicitGrantSettingEnableAccessTokenIssuance" = $true
"ImplicitGrantSettingEnableIdTokenIssuance" = $true
"RequiredResourceAccess" = $requiredResourceAccess
"WebLogoutUrl" = "https://localhost:5050/LogoutView"
"WebRedirectUris" = $webRedirectUris
"IdentifierUris" = "https://$b2cTenantName.onmicrosoft.com/app"
}
# We need to create our application before we can add permissions to our custom scope
$mgApplication = New-MgApplication #mgApplicationParams
# Now our application has an Id so we can finish setting up the RequiredResourceAccess
$newRequiredResourceAccess = $requiredResourceAccess + #{
"ResourceAppId" = $mgApplication.AppId
"ResourceAccess" = $appLoginScope
}
# Azure doesn't always update immediately, make sure app exists before we try to update its config
$appExists = $false
while (!$appExists) {
Start-Sleep -Seconds 2
$appExists = Get-MgApplication -ApplicationId $mgApplication.Id
}
$mgApplicationParams.Add("ApplicationId", $mgApplication.Id)
$mgApplicationParams.RequiredResourceAccess = $newRequiredResourceAccess
Update-MgApplication #mgApplicationParams
$appServicePrincipal = New-MgServicePrincipal -AppId $mgApplication.AppId -Tags #("WindowsAzureActiveDirectoryIntegratedApp")
$result = New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $appServicePrincipal.Id `
-AppRoleId 19dbc75e-c2e2-444c-a770-ec69d8559fc7 `
-ResourceId 429a2356-9cdc-475e-8caf-cfe8b7c77db8 `
-PrincipalType "ServicePrincipal"
# #TODO Generate app client secret
$appClientSecret = "--SECRET--"
Write-Host "Created the app registration ${customerName}-${deploymentIdentifier} with client Id:",
$mgApplication.AppId -ForegroundColor Yellow
#{
"appClientId" = $mgApplication.AppId
"appClientSecret" = $appClientSecret
}
}
Turns out I did not need to assign a role to my service principal for it work and everything to show up correctly. It was a combination of Azure's UI being laggy and also key was adding the Tag in the service principal, which when I posted this I had not yet tested.
I am total newbie to PowerShell, Thycotic Secret Server and writing APIs. I have been tasked with writing an API to remotely access Thycotic Secret Server and upload a secret together with attached files. Unfortunately, I haven’t gotten off the starting block. I am following the code here:
https://thycotic.force.com/support/s/article/REST-API-PowerShell-Scripts-Getting-Started
I have copied down:
3 – Searching Secrets
4 – Create Secret and
Get-Token from here:
https://thycotic.force.com/support/s/article/Secret-Server-Trial-Using-the-API
and have created functions for each one. The only changes I made are to change myurl, myusername and mypassword.
This is my PowerShell script:
$myUrl = "mysecretserver/Login.aspx?ReturnUrl=%2f"
$application = "https://mysecretserver/Login.aspx?ReturnUrl=%2fsecretserver"
# Ask for user name
$userName = Read-Host -Prompt "Please enter user name"
$userPassword = Read-Host -AsSecureString "Password"
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
Get-Token
Search-Secrets $userName,$userPassword
Create-Secret $userName,$userPassword
When I run Get-Token (no changes made to downloaded code)
function Get-Token
{
[CmdletBinding()]
Param(
[Switch] $UseTwoFactor
)
$creds = #{
username = $userName
password = $userPassword
grant_type = "password"
};
$headers = $null
If ($UseTwoFactor) {
$headers = #{
"OTP" = (Read-Host -Prompt "Enter your OTP for 2FA (displayed in your 2FA app): ")
}
}
try
{
$response = Invoke-RestMethod "$application/oauth2/token" -Method Post -Body $creds -Headers $headers;
$token = $response.access_token;
return $token;
}
catch
{
$result = $_.Exception.Response.GetResponseStream();
$reader = New-Object System.IO.StreamReader($result);
$reader.BaseStream.Position = 0;
$reader.DiscardBufferedData();
$responseBody = $reader.ReadToEnd() | ConvertFrom-Json
Write-Host "ERROR: $($responseBody.error)"
return;
}
}
It seems to run ok but when I display $token, it is empty.
I'm not 100% sure what this is doing and have looked at a lot of examples but seem to be missing the basic steps for reading the token and using it to access the secret server. Any help would be greatly appreciated.
Replace your Secret Server URL with the Server's FQDN, not the web URL you get in a browser. You need to make sure the Secret Server address is correct otherwise it won't be hitting the API (and maybe failing gracefully which is why you don't see any errors from the Get-Token function).
For example, instead of:
$application = "https://mysecretserver/Login.aspx?ReturnUrl=%2fsecretserver"
It may be something like:
$application = "https://mysecretserver.mydomain.com"
Requirement: Would like to have basic auth setup using custom php script.
Would like to :
Create user credentials dynamically
Create the cred php file with these credentials updated
Update the username & password to respective for Azure WebApp settings.
[ Note: FTPing the cred and auth files automatically if missing would be in upcoming post ]
Tools & Pre-requisites :
Azure Powershell 4.0+
Windows Powershell ISE
Knowledge of Storage Account ( Name, RG's )
Knowledge of WebApp for which backup is desired ( WebApp Name and RG )
Valid & Active Azure portal / AD login credentials
RESULT : On Azure Portal, The webapp in focus would have 'global_cred' variable key set with credentials generated stored as its value in application settings section as [username:password] format.
#######################
# Function to Generate dynamic 22char random string for password use
# Call custom function to write php constants for basic auth
Function writeFocusDomainCredFile{
param( $configObject, $hash, $farmprojectname )
#setting auth username:password
$configObject.authPasswordKey = (Get-RandomAlphanumericString -length 22 | Tee-Object -variable teeTime )
$hash['global_cred'] = [String]( $configObject.authUsernameKey + ':' + $configObject.authPasswordKey )
$prfilename = ( $configObject.ftpappdirectory + '\cred.php')
writeProjectBasicAuthCredOnNew -filename $prfilename -configObject $configObject
}
##########################
# Function to write the credentials to cred php file for basic auth use
# This file with other dependent files could be automatically ftp'd.
# Would share in another post
Function writeProjectBasicAuthCredOnNew{
param( $filename
,$configObject
)
writeDeployFileFiltersForDomain -ReportFileName $filename
Add-Content $filename ( "<?php" )
Add-Content $filename ("define('WPIZED_AUTH_USER', '" + $configObject.authUsernameKey + "');");
Add-Content $filename ("define('WPIZED_AUTH_PASS', '" + $configObject.authPasswordKey + "');");
}
###################################################################################################
# Configure Below as You prefer or desire #
$properties = #{
'ResourceName' = "AzureAppName";
'myResourceGroupName' = "{App Resource Group Name}";
'mySubscriptionName' = "{subscription name}";
'adminEmail' = "H.Bala#volunteering.com";
'ResourceGroupLocation' = "East US";
'authUsernameKey' = 'HBalaUsername'; #For this post, using fixed username as 'HBalaUsername'
'authPasswordKey' = '';
'PathFormatDate' = Get-Date -UFormat "%Y_%m_%d";
}
$configObject = New-Object –TypeName PSObject –Prop $properties
Write-Output $configObject
#Login cmdlet for active session
Login-AzureRmAccount
Get-AzureRmSubscription –SubscriptionName $configObject.mySubscriptionName | Select-AzureRmSubscription
(Get-AzureRmContext).Subscription
Select-AzureRMSubscription -SubscriptionName $configObject.mySubscriptionName
#Pull the Webapp details and configuration
$webApp = Get-AzureRMWebApp -ResourceGroupName $configObject.myResourceGroupName -Name $configObject.ResourceName
#Pull the Application Listing Environment / Configuration Variables
$appSettingList = $webApp.SiteConfig.AppSettings
$hash = #{}
ForEach ($kvp in $appSettingList) {
$hash[$kvp.Name] = $kvp.Value
}
writeFocusDomainCredFile -configObject $configObject -hash $hash
#[FTP Deploy Logic of this file and other basic auth or files shall cover in seperate topic ]
#[ Only setting the generated Credentials and saving to Application setting focused here ]
Set-AzureRMWebApp -ResourceGroupName $configObject.myResourceGroupName -Name $configObject.ResourceName -AppSettings $hash
Disclaimer: The intention is to share to another newbie who might find this helpful.
I'm attempting to enable IaaS VM backup in Azure using a Recovery Services Vault and it fails when attempting to create a new Protection Policy using Azure New-AzureRmRecoveryServicesBackupProtectionPolicy.
The script has worked for a previous subscription and VMs, so I'm unclear why it doesn't work for this subscription. I've run Azure New-AzureRmRecoveryServicesBackupProtectionPolicy -Debug which returns the below additional information, unfortunately that's not enough to highlight and resolve the problem either:
"error": {
"code": "InvalidRestApiParameter",
"message": "stampId parameter is invalid.\r\nPlease provide a valid stampId",
"target": null,
"details": null,
"innerError": null
}
Here's the code which attempts to create the Protection Policy:
# Create Retention Policy object. Has to be modified from existing 'default' values provided by Azure
$RetPol = Get-AzureRmRecoveryServicesBackupRetentionPolicyObject -WorkloadType "AzureVM"
$BackupTime = (Get-Date).ToUniversalTime().Date.AddHours(23)
$Day = $true
$DayTime = $BackupTime
$DayRet = 7
$Week = $true
$WeekDay = 'Sunday'
$WeekTime = $BackupTime
$WeekRet = 5
$Month = $true
$MonthType = 'Daily'
$MonthTime = $BackupTime
$MonthDay = New-Object -TypeName PSObject -Property #{
Date = 0;
IsLast = $true;
}
$MonthRet = 3
$Year = $false
$RetPol.IsDailyScheduleEnabled = $Day
$RetPol.DailySchedule.DurationCountInDays = $DayRet
$RetPol.DailySchedule.RetentionTimes[0] = $DayTime
$RetPol.IsWeeklyScheduleEnabled = $Week
$RetPol.WeeklySchedule.DaysOfTheWeek = $WeekDay
$RetPol.WeeklySchedule.DurationCountInWeeks = $WeekRet
$RetPol.WeeklySchedule.RetentionTimes[0] = $WeekTime
$RetPol.IsMonthlyScheduleEnabled = $Month
$RetPol.MonthlySchedule.RetentionScheduleFormatType = $MonthType
$RetPol.MonthlySchedule.RetentionScheduleDaily.DaysOfTheMonth = $MonthDay
$RetPol.MonthlySchedule.DurationCountInMonths = $MonthRet
$RetPol.MonthlySchedule.RetentionScheduleWeekly = $null
$RetPol.MonthlySchedule.RetentionTimes[0] = $MonthTime
$RetPol.IsYearlyScheduleEnabled = $Year
$RetPol.YearlySchedule = $null
# Create Schedule Policy object.
$SchPol = Get-AzureRmRecoveryServicesBackupSchedulePolicyObject -WorkloadType "AzureVM"
$SchPol.ScheduleRunFrequency = "Daily"
$SchPol.ScheduleRunDays = $null
$SchPol.ScheduleRunTimes[0] = $BackupTime
#Create the new Backup Policy
$BackupPolicy = New-AzureRmRecoveryServicesBackupProtectionPolicy -WorkloadType AzureVM -Name 'MyPolicy' -RetentionPolicy $RetPol -SchedulePolicy $SchPol
Any help or thoughts greatly appreciated.
TL;DR: Deleted and re-created the Recovery Services Vault via PowerShell
Full Description
Turned-out that something had previously gone wrong with the creation of the Recovery Services Vault, which wasn't clear when I'd run New-AzureRmRecoveryServicesVault but had resulted in the following view of the RSV when opened via the Portal:
The RSV wouldn't delete via the portal so I had to use Remove-AzureRmRecoveryServicesVault to remove it. I then re-created it, which resolved the error and allowed me to backup the VMs
I am currently trying to send an email through powershell with a populated mileage field in order for outlook to pick up on.
The email goes through fine but I am unable to get a value through for the 'Mileage' Field.
$SMTPName = ''
$EmailMessage = new-object Net.Mail.MailMessage
$SMTPServer = new-object Net.Mail.SmtpClient($SMTPName)
$EmailMessage.Headers.Add("Mileage", "HB")
$EmailMessage.From = ''
$EmailMessage.To.Add('')
$EmailMessage.Subject = $sub
$EmailMessage.Body = $body
$EmailMessage.Priority = [System.Net.Mail.MailPriority]::High
$SMTPServer.Send($EmailMessage)
Mileage is a MAPI property so you will need to send the message with either Outlook or EWS eg the following should work to send a message with that property set in EWS
## Get the Mailbox to Access from the 1st commandline argument
$MailboxName = $args[0]
## Load Managed API dll
Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"
## Set Exchange Version
$ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
## Create Exchange Service Object
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
## Set Credentials to use two options are availible Option1 to use explict credentials or Option 2 use the Default (logged On) credentials
#Credentials Option 1 using UPN for the windows Account
$psCred = Get-Credential
$creds = New-Object System.Net.NetworkCredential($psCred.UserName.ToString(),$psCred.GetNetworkCredential().password.ToString())
$service.Credentials = $creds
#Credentials Option 2
#service.UseDefaultCredentials = $true
## Choose to ignore any SSL Warning issues caused by Self Signed Certificates
## Code From http://poshcode.org/624
## Create a compilation environment
$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler=$Provider.CreateCompiler()
$Params=New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable=$False
$Params.GenerateInMemory=$True
$Params.IncludeDebugInformation=$False
$Params.ReferencedAssemblies.Add("System.DLL") | Out-Null
$TASource=#'
namespace Local.ToolkitExtensions.Net.CertificatePolicy{
public class TrustAll : System.Net.ICertificatePolicy {
public TrustAll() {
}
public bool CheckValidationResult(System.Net.ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
System.Net.WebRequest req, int problem) {
return true;
}
}
}
'#
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly
## We now create an instance of the TrustAll and attach it to the ServicePointManager
$TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll
## end code from http://poshcode.org/624
## Set the URL of the CAS (Client Access Server) to use two options are availbe to use Autodiscover to find the CAS URL or Hardcode the CAS to use
#CAS URL Option 1 Autodiscover
$service.AutodiscoverUrl($MailboxName,{$true})
"Using CAS Server : " + $Service.url
#CAS URL Option 2 Hardcoded
#$uri=[system.URI] "https://casservername/ews/exchange.asmx"
#$service.Url = $uri
## Optional section for Exchange Impersonation
#$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)
$EmailMessage = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage -ArgumentList $service
$EmailMessage.Subject = "Message Subject"
#Add Recipients
$EmailMessage.ToRecipients.Add("user#domain.com")
$EmailMessage.Body = New-Object Microsoft.Exchange.WebServices.Data.MessageBody
$EmailMessage.Body.BodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::HTML
$EmailMessage.Body.Text = "Body"
$Mileage = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([Microsoft.Exchange.WebServices.Data.DefaultExtendedPropertySet]::Common,34100,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String);
$EmailMessage.SetExtendedProperty($Mileage,"HB")
$EmailMessage.SendAndSaveCopy() enter code here