I am trying to get credentials straight out of Thycotic Secret Server through powershell instead of copying and pasting each and every username/password. Has anyone came across this before?
I wrote a function just for this type of thing.
Mandatory fields are
-Webservice which needs to be point to sswebservice.asmx usually located as https://{Base Address}/webservices/sswebservice.asmx
-Credential which is your Thycotic login.
-searchTerm which is the string you are searching for.
function Get-Secret{
Param (
[Parameter(Mandatory=$False)]
[string] $WebService,
[Parameter(Mandatory=$True)]
[pscredential] $Credential,
[string] $Organization = $Null,
[Parameter(Mandatory=$True)]
[string] $SearchTerm = $Null,
[Parameter(ParameterSetName='Only',Mandatory=$false)]
[switch] $CountOnly,
[Parameter(ParameterSetName='Only',Mandatory=$false)]
[switch] $SummeryOnly,
[switch] $Raw
)
$Service = New-WebServiceProxy -uri $WebService -UseDefaultCredential
$LoginResult = $Service.Authenticate($($Credential.GetNetworkCredential().Username), $($Credential.GetNetworkCredential().Password), $Organization, $($Credential.GetNetworkCredential().Domain))
if($LoginResult.errors){
throw $LoginResult.errors
return
}
$Secret_IDs = $Service.SearchSecrets($LoginResult.token, $searchTerm, $true, $true)
if($Secret_IDs.errors){
throw $Secret_IDs.errors
return
}
if($CountOnly){
return $Secret_IDs.SecretSummaries.count
}
if($SummeryOnly){
return $Secret_IDs.SecretSummaries
}
$Response = #()
foreach($Secret_ID in $Secret_IDs.SecretSummaries){
$Secret = $Service.GetSecret($LoginResult.token, $Secret_ID.SecretID, $false, $null).secret
$Response += $Secret
}
if($Raw){
return $Response
}else{
return $Response | Foreach-object{
Write-Output "$($_.Name)"
Foreach($item in $_.Items){
Write-Output "$($item.FieldDisplayName) : $($item.Value)"
}
Write-Output "`r`n"
}
}
}
Basic Usage
Get-Secret -WebService "https://Stuff/sswebservice.asmx" -Credential $ThycoticCredentials -SearchTerm "HELLO"
Other usages is the parameter -raw. This will return an object based on the return from Thycotic.
You can narrow down to the field items
Get-Secret -WebService "https://Stuff/sswebservice.asmx" -Credential $ThycoticCredentials -SearchTerm "HELLO" -raw | select -ExpandProperty Items
And even narrow down to values (this one getting field Username)
Get-Secret -WebService "https://Stuff/sswebservice.asmx" -Credential $ThycoticCredentials -SearchTerm "HELLO" -raw | select -ExpandProperty Items | ?{$_.fieldname -like 'username'} | select -ExpandProperty value
Related
So here is my code to get the AuthToken for my Tenant ID, this is from Microsoft and generates a JWT to use as authorization in the HTTP header:
function Get-AuthToken {
[cmdletbinding()]
param
(
[Parameter(Mandatory=$true)]
$User
)
$userUpn = New-Object "System.Net.Mail.MailAddress" -ArgumentList $User
$tenant = $userUpn.Host
Write-Host "Checking for AzureAD module..."
$AadModule = Get-Module -Name "AzureAD" -ListAvailable
if ($AadModule -eq $null) {
Write-Host "AzureAD PowerShell module not found, looking for AzureADPreview"
$AadModule = Get-Module -Name "AzureADPreview" -ListAvailable
}
if ($AadModule -eq $null) {
write-host
write-host "AzureAD Powershell module not installed..." -f Red
write-host "Install by running 'Install-Module AzureAD' or 'Install-Module AzureADPreview' from an elevated PowerShell prompt" -f Yellow
write-host "Script can't continue..." -f Red
write-host
exit
}
if($AadModule.count -gt 1){
$Latest_Version = ($AadModule | select version | Sort-Object)[-1]
$aadModule = $AadModule | ? { $_.version -eq $Latest_Version.version }
# Checking if there are multiple versions of the same module found
if($AadModule.count -gt 1){
$aadModule = $AadModule | select -Unique
}
$adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
}else {
$adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
}
[System.Reflection.Assembly]::LoadFrom($adal) | Out-Null
[System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null
$clientId = "d1ddf0e4-d672-4dae-b554-9d5bdfd93547"
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$Tenant"
try {
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto"
$userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($User, "OptionalDisplayableId")
$authResult = $authContext.AcquireTokenAsync($resourceAppIdURI,$clientId,$redirectUri,$platformParameters,$userId).Result
# If the accesstoken is valid then create the authentication header
if($authResult.AccessToken){
# Creating header for Authorization token, we dont necessarily need it, just the JWT auth token.
$authHeader = #{
'Content-Type'='application/json'
'Authorization'="Bearer " + $authResult.AccessToken
'ExpiresOn'=$authResult.ExpiresOn
}
# Write-Output
return $authResult
# return $authHeader
}
}catch {
write-host $_.Exception.Message -f Red
break
}
}
So basically at the bottom I use this JWT auth token from the function above and place it as an Authorization field in the HTTP header and it should return JSON from the Graph API:
$authData = Get-AuthToken -User acct#pennitout.com
$accessJWToken = $authData.AccessToken
$apiUrl = "https://graph.microsoft.com/v1.0/users?$select=displayName"
Invoke-RestMethod -Headers #{"Authorization" = "Bearer $accessJWToken"} -Uri $apiUrl -Method Get -ContentType "application/json"
And the above code beautifully absolutely uselessly output it returns instead is:
#odata.context #odata.nextLink
-------------- ---------------
https://graph.microsoft.com/v1.0/$metadata#users https://graph.microsoft.com/v1.0/users?=displayName&$skiptoken=RFNwdAIAAQAAABg6YWdyYW50QHRlcnJhbmV1dHJhbC5jb20pVXNlcl85MzA2OWJlYy0zZjFjLTRiNDQtOTZjMS
Please Help with this thanks I really appreciate
Can you please check there might be issue that Token has expired, Please try to generate new token and check it for the Odata next link which might have caused the error.
Here is the document for reference:Token Duration
i have a script that works fine for exchange on-prem and online with basic auth.
The problem is that my organization now accetps only oAuth metod for echangeonline.
This script is for insert a quickaction in the user logging with in his mailbox.
How i have to change the connect method to work with oauth within exchangeonline?
i'll have the same commandelets after that?
Begin
{
Import-Module Activedirectory
}
Process
{
$curUser = $env:USERNAME
$curDomain = $env:USERDNSDOMAIN
$aUser = Get-ADUser -Identity "${curUser}" -Server "${curDomain}" -Properties "EmailAddress"
if ([string]::IsNullOrEmpty($aUser.EmailAddress)) {
throw "User ${curUser} has no Emailaddress"
}
$aUser.EmailAddress
"$($aUser.GivenName) $($aUser.Surname)"
}
}
function Connect-Exchange{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName
)
try {
Connect-Exchange365 -MailboxName $MailboxName
} catch {
Connect-ExchangeONPREM -MailboxName $MailboxName
}
}
function Connect-Exchange365
{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName
)
Begin
{
############## NEW CODE HERE WITH OAUTH ################
$service = "?????????????????"
if (!$service.URL) {
throw "Error connecting to EWS"
}
else
{
return $service
}
}
}
function Connect-ExchangeONPREM
{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName
)
Begin
{
## Load Managed API dll
###CHECK FOR EWS MANAGED API, IF PRESENT IMPORT THE HIGHEST VERSION EWS DLL, ELSE EXIT
$EWSDLL = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services'|Sort-Object Name -Descending| Select-Object -First 1 -ExpandProperty Name)).'Install Directory') + "Microsoft.Exchange.WebServices.dll")
if (Test-Path $EWSDLL)
{
Import-Module $EWSDLL
}
else
{
"$(get-date -format yyyyMMddHHmmss):"
"This script requires the EWS Managed API 1.2 or later."
"Please download and install the current version of the EWS Managed API from"
"http://go.microsoft.com/fwlink/?LinkId=255472"
""
"Exiting Script."
exit
}
## 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($Credentials.UserName.ToString(),$Credentials.GetNetworkCredential().password.ToString())
############ $service.Credentials = $creds
#Credentials Option 2
$service.UseDefaultCredentials = $true
$service.TraceEnabled = $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})
Write-host ("Using CAS Server : " + $Service.url)
## Optional section for Exchange Impersonation
#$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)
if(!$service.URL){
throw "Error connecting to EWS"
}
else
{
return $service
}
}
}
function ConvertFolderid{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$hexid,
[Parameter(Position=1, Mandatory=$true)] [Microsoft.Exchange.WebServices.Data.ExchangeService]$service,
[Parameter(Position=2, Mandatory=$true)] [string]$MailboxName
)
Begin
{
$aiItem = New-Object Microsoft.Exchange.WebServices.Data.AlternateId
$aiItem.Mailbox = $MailboxName
$aiItem.UniqueId = $hexId
$aiItem.Format = [Microsoft.Exchange.WebServices.Data.IdFormat]::HexEntryId;
return $global:service.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::EWSId)
}
}
#######################
<#
.SYNOPSIS
Gets the QuickSteps folder in a Mailbox using the Exchange Web Services API
.DESCRIPTION
Gets the QuickSteps folder in a Mailbox using the Exchange Web Services API
Requires the EWS Managed API from https://www.microsoft.com/en-us/download/details.aspx?id=42951
.EXAMPLE
Example 1 To Gets the QuickSteps folder in a Mailbox using the Exchange Web Services API
Get-QuickStepsFolder -MailboxName mailbox#domain.com
#>
########################
function Get-QuickStepsFolder
{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=1, Mandatory=$false)] [Microsoft.Exchange.WebServices.Data.ExchangeService]$service
)
Begin
{
#if(!$service){
$localservice = Connect-Exchange -MailboxName $MailboxName
#}
$PidTagAdditionalRenEntryIdsEx = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x36D9, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary)
$psPropset = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$psPropset.Add($PidTagAdditionalRenEntryIdsEx)
$folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName)
try {
$IPM_ROOT = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($localservice,$folderid,$psPropset)
} catch {
$localservice = Connect-ExchangeONPREM -MailboxName $MailboxName
$IPM_ROOT = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($localservice,$folderid,$psPropset)
}
$global:service = $localservice
$binVal = $null;
$AdditionalRenEntryIdsExCol = #{}
if($IPM_ROOT.TryGetProperty($PidTagAdditionalRenEntryIdsEx,[ref]$binVal)){
$hexVal = [System.BitConverter]::ToString($binVal).Replace("-","");
##Parse Binary Value first word is Value type Second word is the Length of the Entry
$Sval = 0;
while(($Sval+8) -lt $hexVal.Length){
$PtypeVal = $hexVal.SubString($Sval,4)
$PtypeVal = $PtypeVal.SubString(2,2) + $PtypeVal.SubString(0,2)
$Sval +=12;
$PropLengthVal = $hexVal.SubString($Sval,4)
$PropLengthVal = $PropLengthVal.SubString(2,2) + $PropLengthVal.SubString(0,2)
$PropLength = [Convert]::ToInt64($PropLengthVal, 16)
$Sval +=4;
$ProdIdEntry = $hexVal.SubString($Sval,($PropLength*2))
$Sval += ($PropLength*2)
#$PtypeVal + " : " + $ProdIdEntry
$AdditionalRenEntryIdsExCol.Add($PtypeVal,$ProdIdEntry)
}
}
$QuickStepsFolder = $null
if($AdditionalRenEntryIdsExCol.ContainsKey("8007")){
$siId = ConvertFolderid -service $service -MailboxName $MailboxName -hexid $AdditionalRenEntryIdsExCol["8007"]
$QuickStepsFolderId = new-object Microsoft.Exchange.WebServices.Data.FolderId($siId.UniqueId.ToString())
$QuickStepsFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($global:service,$QuickStepsFolderId)
}
else{
Write-Host ("QuickSteps folder not found")
throw ("QuickSteps folder not found")
}
write-host "end of Get-QuickStepsFolder"
write-host " ---FLD --- $($QuickStepsFolder.DisplayName)"
return $QuickStepsFolder
}
}
function Get-ExistingStepNames{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=1, Mandatory=$true)] [Microsoft.Exchange.WebServices.Data.Folder]$QuickStepsFolder
)
Begin
{
$NameList = #{}
$enc = [system.Text.Encoding]::ASCII
$PR_ROAMING_XMLSTREAM = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x7C08,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary);
$psPropset= new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$psPropset.Add($PR_ROAMING_XMLSTREAM)
#Define ItemView to retrive just 1000 Items
$ivItemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(1000)
$ivItemView.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Associated
$fiItems = $null
do{
$fiItems = $QuickStepsFolder.FindItems($ivItemView)
if($fiItems.Items.Count -gt 0){
[Void]$global:service.LoadPropertiesForItems($fiItems,$psPropset)
foreach($Item in $fiItems.Items){
$propval = $null
if($Item.TryGetProperty($PR_ROAMING_XMLSTREAM,[ref]$propval)){
[XML]$xmlVal = $enc.GetString($propval)
if(!$NameList.ContainsKey($xmlVal.CombinedAction.Name.ToLower())){
$NameList.Add($xmlVal.CombinedAction.Name.Trim().ToLower(),$xmlVal)
}
}
}
}
$ivItemView.Offset += $fiItems.Items.Count
}while($fiItems.MoreAvailable -eq $true)
return $NameList
}
}
function Get-ExistingSteps{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=1, Mandatory=$true)] [Microsoft.Exchange.WebServices.Data.Folder]$QuickStepsFolder
)
Begin
{
$NameList = #{}
$enc = [system.Text.Encoding]::ASCII
$PR_ROAMING_XMLSTREAM = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x7C08,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary);
$psPropset= new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$psPropset.Add($PR_ROAMING_XMLSTREAM)
#Define ItemView to retrive just 1000 Items
$ivItemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(1000)
$ivItemView.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Associated
$fiItems = $null
do{
$fiItems = $QuickStepsFolder.FindItems($ivItemView)
if($fiItems.Items.Count -gt 0){
[Void]$global:service.LoadPropertiesForItems($fiItems,$psPropset)
foreach($Item in $fiItems.Items){
$propval = $null
if($Item.TryGetProperty($PR_ROAMING_XMLSTREAM,[ref]$propval)){
[XML]$xmlVal = $enc.GetString($propval)
if(!$NameList.ContainsKey($xmlVal.CombinedAction.Name.ToLower())){
$NameList.Add($xmlVal.CombinedAction.Name.Trim().ToLower(),$Item)
}
}
}
}
$ivItemView.Offset += $fiItems.Items.Count
}while($fiItems.MoreAvailable -eq $true)
return $NameList
}
}
#######################
<#
.SYNOPSIS
Gets the existing Outlook Quick Steps from a Mailbox using the Exchange Web Services API
.DESCRIPTION
Gets the existing Outlook Quick Steps from a Mailbox using the Exchange Web Services API
Requires the EWS Managed API from https://www.microsoft.com/en-us/download/details.aspx?id=42951
.EXAMPLE
Example 1 To Gets the existing Outlook Quick Steps from a Mailbox using the Exchange Web Services API
Get-QuickSteps -MailboxName mailbox#domain.com
This returns a HashTable of the QuickSteps to access a Quickstep within the collection use the Index value eg
$QuickSteps = Get-QuickSteps -MailboxName mailbox#domain.com
$QuickSteps["clutter"]
#>
########################
function Get-QuickSteps{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName
)
Begin{
#Connect
#$service = Connect-Exchange -MailboxName $MailboxName -Credential $Credentials
$QuickStepsFolder = Get-QuickStepsFolder -MailboxName $MailboxName -service $global:service
$ExistingSteps = Get-ExistingStepNames -MailboxName $MailboxName -QuickStepsFolder $QuickStepsFolder
Write-Output $ExistingSteps
}
}
#######################
<#
.SYNOPSIS
Exports an Outlook Quick Step XML settings from a QuickStep Item in a Mailbox using the Exchange Web Services API
.DESCRIPTION
Exports an Outlook Quick Step XML settings from a QuickStep Item in a Mailbox using the Exchange Web Services API
Requires the EWS Managed API from https://www.microsoft.com/en-us/download/details.aspx?id=42951
.EXAMPLE
Example 1 Exports an Outlook Quick Step XML settings from a QuickStep Item in a Mailbox to a file
Export-QuickStepXML -MailboxName mailbox#domain -Name 'Name of QuickStep' -FileName c:\temp\exportFile.xml
#>
########################
function Export-QuickStepXML{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=1, Mandatory=$true)] [string]$Name,
[Parameter(Position=2, Mandatory=$true)] [string]$FileName
)
Begin{
#Connect
#$service = Connect-Exchange -MailboxName $MailboxName -Credential $Credentials
$QuickStepsFolder = Get-QuickStepsFolder -MailboxName $MailboxName -service $global:service
$ExistingSteps = Get-ExistingSteps -MailboxName $MailboxName -QuickStepsFolder $QuickStepsFolder
if($ExistingSteps.ContainsKey($Name.Trim().ToLower())){
$PR_ROAMING_XMLSTREAM = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x7C08,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary);
$psPropset= new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$psPropset.Add($PR_ROAMING_XMLSTREAM)
$propval = $null
if($ExistingSteps[$Name.Trim().ToLower()].TryGetProperty($PR_ROAMING_XMLSTREAM,[ref]$propval)){
[System.IO.File]::WriteAllBytes($FileName,$propval)
Write-Host ('Exported to ' + $FileName)
}
}
}
}
function Create-QuickStepFromXML
{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=1, Mandatory=$true)] [String]$XMLFileName
)
Begin
{
#Connect
[xml]$QuickStepXML = Get-Content -Path $XMLFileName
$DisplayName = $QuickStepXML.CombinedAction.Name
$Name = $QuickStepXML.CombinedAction.Name.ToLower()
$service = Connect-Exchange -MailboxName $MailboxName
$QuickStepsFolder = Get-QuickStepsFolder -MailboxName $MailboxName -service $service
$QuickStepItem = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage -ArgumentList $global:service
$QuickStepItem.ItemClass = "IPM.Microsoft.CustomAction"
$ExistingSteps = Get-ExistingStepNames -MailboxName $MailboxName -QuickStepsFolder $QuickStepsFolder
if(!$ExistingSteps.ContainsKey($Name.Trim().ToLower())){
$PR_ROAMING_XMLSTREAM = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x7C08,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary);
$enc = [system.Text.Encoding]::ASCII
$QuickStepItem.SetExtendedProperty($PR_ROAMING_XMLSTREAM,$enc.GetBytes((Get-Content -Path $XMLFileName)))
$QuickStepItem.IsAssociated = $true
$QuickStepItem.Save($QuickStepsFolder.Id)
Write-host
Write-host ("SUCCESS Created QuickStep " + $DisplayName)
}
else
{
Write-host
Write-host ("FAILED: QuickStep with name " + $DisplayName + " already exists")
# throw ("Step with Name " + $DisplayName + " already exists")
}
}
}
#######################
<#
.SYNOPSIS
Deletes an Outlook Quick Step from a Mailbox using the Exchange Web Services API
.DESCRIPTION
Deletes an Outlook Quick Step from a Mailbox using the Exchange Web Services API
Requires the EWS Managed API from https://www.microsoft.com/en-us/download/details.aspx?id=42951
.EXAMPLE
Example 1 To Delete an Outlook Quick Step from a Mailbox give the name of the Quickstep
Delete-QuickStep -MailboxName mailbox#domain -Name 'Name of QuickStep'
#>
########################
function Delete-QuickStep{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=1, Mandatory=$true)] [String]$Name
)
Begin
{
#Connect
$service = Connect-Exchange -MailboxName $MailboxName
$QuickStepsFolder = Get-QuickStepsFolder -MailboxName $MailboxName -service $service
$ExistingSteps = Get-ExistingSteps -MailboxName $MailboxName -QuickStepsFolder $QuickStepsFolder
if($ExistingSteps.ContainsKey($Name.Trim().ToLower())){
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes",""
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No",""
$choices = [System.Management.Automation.Host.ChoiceDescription[]]($yes,$no)
$message = "Do you want to Delete QuickStep with Name " + $Name.Trim()
$result = $Host.UI.PromptForChoice($caption,$message,$choices,1)
if($result -eq 0) {
$ExistingSteps[$Name.Trim().ToLower()].Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
Write-Host ("QuickStep Deleted")
}
else{
Write-Host ("No Action Taken")
}
}
else{
Write-Host -ForegroundColor Yellow ("No QuickStep found")
}
}
}
########### MAIN #############
$XML_QuickStepsContent=#'
<?xml version="1.0"?>
<CombinedAction Ordinal="200" Tooltip="" Icon="FileSendAsAttachment" Name="Sign as SPAM" Version="154433">
<ActionForwardAsAttach>
<Subject>TEST - PLS IGNORE: <Subject></Subject>
<Location/>
<Body/>
<Send>1</Send>
<FlagDays>0</FlagDays>
<Recipient>
<EntryId>00000000DCA740C8C042101AB4B908002B2FE18201000000000000002F6F3D4D41494C2F6F753D45786368616E67652041646D696E6973747261746976652047726F7570202846594449424F484632335350444C54292F636E3D526563697069656E74732F636E3D4D62782047454152202847654F5320456D61696C20416E616C7973697320616E6420526573706F6E73652962616500</EntryId>
</Recipient>
</ActionForwardAsAttach>
<ActionMoveToFolder>
<Folder>800101012E000000A486FB38C9000000D286FB380000000020C51E61B74A4A44921273CE8E5927E30100293C04FDADC95F4FBF47717FB2F56B5B00000068F0D500000000000038A1BB1005E5101AA1BB08002B2A56C20000454D534D44422E444C4C00000000000000001B55FA20AA6611CD9BC800AA002FC45A0C00000033323136343731352D343937622D346665382D623535632D3731323539636665646264624065787465726E616C2E656E692E636F6D002F6F3D4D41494C2F6F753D45786368616E67652041646D696E6973747261746976652047726F7570202846594449424F484632335350444C54292F636E3D526563697069656E74732F636E3D434F323933353065333400</Folder>
</ActionMoveToFolder>
</CombinedAction>
'#
try {
$mailAdddress, $username = getCurrentUserMailboxAndName
$res = read-host "Create quick steps for ${username} mailbox ${mailAdddress}? [y|N]"
if ("y" -eq $res.toLower()) {
$tmpFile = New-TemporaryFile
Out-File -FilePath $tmpFile.FullName -InputObject $XML_QuickStepsContent
Create-QuickStepFromXML $mailAdddress -XMLFileName $tmpFile.FullName
Remove-Item $tmpFile
} else {
Write-Host
Write-Host "Nothing to do"
}
} catch {
Write-Host
Write-Host "ERROR: $($_.exception)"
}
Write-Host
$close = read-host "Press Enter to finish"
Write-Host
Write-Host "Script terminated" + $close ``
There are a few ways you could do it probably the easiest is to use the ADAL.dll's eg
Write-Verbose("Using Modern Auth")
if ([String]::IsNullOrEmpty($ClientId)) {
$ClientId = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
}
Import-Module ($script:ModuleRoot + "/bin/Microsoft.IdentityModel.Clients.ActiveDirectory.dll") -Force
$Context = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext("https://login.microsoftonline.com/common")
if ($Credentials -eq $null) {
$PromptBehavior = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters -ArgumentList Auto
$token = ($Context.AcquireTokenAsync("https://outlook.office365.com", $ClientId , "urn:ietf:wg:oauth:2.0:oob", $PromptBehavior)).Result
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.OAuthCredentials($token.AccessToken)
}else{
$AADcredential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserPasswordCredential" -ArgumentList $Credentials.UserName.ToString(), $Credentials.GetNetworkCredential().password.ToString()
$token = [Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContextIntegratedAuthExtensions]::AcquireTokenAsync($Context,"https://outlook.office365.com",$ClientId,$AADcredential).result
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.OAuthCredentials($token.AccessToken)
}
A few other examples https://ingogegenwarth.wordpress.com/2018/08/02/ews-and-oauth/ and https://gsexdev.blogspot.com/2019/10/using-msal-microsoft-authentication.html
I want my function to be able to accumulatively filter data based on parameter input. Here is my attempt:
function Get-People {
[cmdletbinding()]
param(
[parameter(mandatory=$false,position=0)]
[string]$Name,
[parameter(mandatory=$false)]
[string]$Country,
[parameter(mandatory=$false)]
[string]$State,
[parameter(mandatory=$false)]
[string]$City,
[parameter(mandatory=$false)]
[string]$IDNumber
)
$uri = "https://some.site.com/api/endpoint"
$header = $script:HeaderData
$response = invoke-restmethod -uri $uri -header $header -method get -contenttype "application/json"
if ($IDNumber) {$response = $response | ?{$_.idnumber -eq $IDNumber}}
if ($Name) {$response = $response | ?{$_.name -like $Name}}
if ($City) {$response = $response | ?{$_.city -like $City}}
if ($State) {$response = $response | ?{$_.state -like $State}}
if ($Country) {$response = $response | ?{$_.country -like $Country}}
$response
}
This works pretty well. I can run the command below
get-people -Country US -State Texas -City Austin -Name Jo*
and it will return everyone in Austin, TX, US with names starting with "Jo".
It just feels like a really clunky solution, and I'm wondering if there is a better way to do this.
I'd suggest the following approach.
Build a filter according to the passed parameter
Filter the response once with that final filter
To achieve this, you can store the filter script blocks into a list variable, then create a new condition by combining all conditions into one.
The resulting function would look like this
(Note that $FakeResponse was added for the sole purpose of demonstrating the end result with a fake data set since I can't make an API call to your unkwnown API)
function Get-People {
[cmdletbinding()]
param(
$FakeResponse,
[parameter(mandatory = $false, position = 0)]
[string]$Name,
[parameter(mandatory = $false)]
[string]$Country,
[parameter(mandatory = $false)]
[string]$State,
[parameter(mandatory = $false)]
[string]$City,
[parameter(mandatory = $false)]
[string]$IDNumber
)
if ($PSBoundParameters.ContainsKey('FakeResponse')) {
$response = $FakeResponse
}
else {
$uri = "https://some.site.com/api/endpoint"
$header = $script:HeaderData
$response = invoke-restmethod -uri $uri -header $header -method get -contenttype "application/json"
}
$Conditions = [System.Collections.Generic.List[scriptblock]]::new()
Foreach ($k in $PSBoundParameters.Keys) {
switch ($k) {
'Name' { $Conditions.Add( { $_.name -like $Name }) }
'Country' { $Conditions.Add( { $_.country -like $Country }) }
'State' { $Conditions.Add( { $_.state -like $State }) }
'City' { $Conditions.Add( { $_.city -like $City } ) }
'IDNumber' { $Conditions.Add( { $_.idnumber -eq $IDNumber }) }
}
}
if ($Conditions.Count -ge 1) {
$FinalCondition = [scriptblock]::Create(($Conditions -join ' -and '))
Write-Verbose "Filter applied: $($FinalCondition.ToString())"
return $response.Where($FinalCondition)
}
else {
return $Response
}
}
For demonstration purpose, I added a Write-Verbose for the end filter.
Also for demonstration purpose, here's a fake data set to test the function against.
$TestData = #(
[PSCustomObject]#{
Name = 'Morty'
IDNumber = 'C-299'
City = 'Montreal'
State = 'Quebec'
Country = 'Canada'
},
[PSCustomObject]#{
Name = 'Rick'
IDNumber = 'C-137'
City = 'Seattle'
State = 'Washinton'
Country = 'USA'
},
[PSCustomObject]#{
Name = 'Jerry'
IDNumber = '?'
City = 'Seattle'
State = 'Washinton'
Country = 'USA'
}
)
Finally, the actual call:
get-people -City 'Seattle' -Country USA -FakeResponse $TestData -Verbose | ft
And the result:
I am trying to collect user profile information for users on a machine and I was wondering if I could get it with gwmi. Here is how I get printers for the current user:Get-WmiObject win32_printer. How can I get the same info for the user "Test" on the same machine?
As it happens, I can't sleep, so I came up with these 2 functions:
function Get-UserSid {
[CmdletBinding()]
param(
[Parameter(
ParameterSetName='NTAccount',
Mandatory=$true,
ValueFromPipeline=$true,
Position=0
)]
[System.Security.Principal.NTAccount]
$Identity ,
[Parameter(
ParameterSetName='DomainAndUser',
Mandatory=$true
)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^[^\\]+$')]
[String]
$Domain ,
[Parameter(
ParameterSetName='DomainAndUser',
Mandatory=$true
)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^[^\\]+$')]
[String]
$User
)
Begin {
if ($PSCmdlet.ParameterSetName -eq 'DomainAndUser') {
$Identity = New-Object System.Security.Principal.NTAccount -ArgumentList $Domain,$User
}
}
Process {
$Identity.Translate([System.Security.Principal.SecurityIdentifier])
}
}
function Get-PrinterNameByUser {
[CmdletBinding(DefaultParameterSetName='Ambiguous')]
param(
[Parameter(
ParameterSetName='ByAccount',
Mandatory=$true
)]
[System.Security.Principal.NTAccount]
$Account ,
[Parameter(
ParameterSetName='BySID',
Mandatory=$true
)]
[System.Security.Principal.SecurityIdentifier]
$SID ,
[Parameter(
ParameterSetName='Ambiguous',
Mandatory=$true,
Position=0,
ValueFromPipeline=$true
)]
[ValidateNotNullOrEmpty()]
[String]
$Identity
)
Begin {
Write-Verbose "Parameter Set Name: $($PSCmdlet.ParameterSetName)"
if ($PSCmdlet.ParameterSetName -eq 'ByAccount') {
$SID = $Account | Get-UserSid
}
}
Process {
if ($PSCmdlet.ParameterSetName -eq 'Ambiguous') {
try {
$SID = [System.Security.Principal.SecurityIdentifier]$Identity
} catch [System.InvalidCastException] {
$Account = [System.Security.Principal.NTAccount]$Identity
$SID = $Account | Get-UserSid
}
}
Get-ChildItem -Path "Registry::\HKEY_Users\$($SID.Value)\Printers" | Select-Object -ExpandProperty Property -Unique
}
}
Usage
Get-PrinterNameByUser Test
Get-PrinterNameByUser 'domain\test'
Get-PrinterNameByUser 'S-1-S-21-65454546-516413534-4444'
All of those could be piped as well:
'Test' | Get-PrinterNameByUser
'domain\test' | Get-PrinterNameByUser
'S-1-S-21-65454546-516413534-4444' | Get-PrinterNameByUser
'S-1-S-21-65454546-516413534-4444','user1','machine\user2','domain\user3' | Get-PrinterNameByUser
Explanation
In the registry at HKU\S-ID-HERE\Printers there are some keys with properties. The property names are the printers. I wasn't able to test this on enough machines, so I wasn't certain which key(s) I should check, and whether they would be different depending on whether it was a local or network printer, etc., so I'm just getting the properties from all the keys and returning the unique ones.
The helper function Get-UserSid just provides a convenient way to get a SID from a user name.
Most of Get-PrinterNameByUser is just code to figure out what you've given it and translate it at needed. The meat of it that returns what you want is just the one line:
Get-ChildItem -Path "Registry::\HKEY_Users\$($SID.Value)\Printers" | Select-Object -ExpandProperty Property -Unique
If a SharePoint list has a multiple-select user field (DeveloperSecondary):
What is the right way to filter by this field? Both of these queries produce a 404 error:
http://server/_vti_bin/listdata.svc/list?$filter=(DeveloperSecondary/Results/UserName eq 'foo')
http://server/_vti_bin/listdata.svc/list?$filter=(DeveloperSecondary/UserName eq 'foo')
If this was a single-select user field, the OData query would be:
http://server/_vti_bin/listdata.svc/list?$filter=(SingleSelectUserField/UserName eq 'foo')
Unfortunately $filter query option for multi-valued user field is not supported in SharePoint 2010 OData API.
As a workaround you could consider to apply filter to the returned results as demonstrated below:
$requestUrl = "http://contoso.intranet.dev/_vti_bin/listdata.svc/TheList?`$expand=DeveloperSecondary"
$data = Execute-RequestJson -Url $requestUrl -UseDefaultCredentials $true
#filter items
$data.d.results | % { $_.DeveloperSecondary.results | Where-Object {($_.Name -eq 'John Doe')} }
where
Function Execute-RequestJson()
{
Param(
[Parameter(Mandatory=$True)]
[string]$Url,
[Parameter(Mandatory=$False)]
[System.Net.ICredentials]$Credentials,
[Parameter(Mandatory=$False)]
[bool]$UseDefaultCredentials = $True,
[Parameter(Mandatory=$False)]
[Microsoft.PowerShell.Commands.WebRequestMethod]$Method = [Microsoft.PowerShell.Commands.WebRequestMethod]::Get
)
$client = New-Object System.Net.WebClient
if($Credentials) {
$client.Credentials = $Credentials
}
elseif($UseDefaultCredentials){
$client.Credentials = [System.Net.CredentialCache]::DefaultCredentials
}
$client.Headers.Add("Content-Type", "application/json;odata=verbose")
$client.Headers.Add("Accept", "application/json;odata=verbose")
$data = $client.DownloadString($Url)
$client.Dispose()
return $data | ConvertFrom-Json
}