@@ -28,6 +28,7 @@ Updated error output
28
28
2023-06-25 - Updated to add WideAccountsSearch, NarrowSearch, ignoreAccountName
29
29
2025-01-07 - Updated to allow automatically not create duplicates, fix bad record handling, formating update
30
30
2025-03-17 - Updated to allow for verbose output to a file
31
+ 2025-04-30 - Updated to check and correct URL scheme and path for Privilege Cloud
31
32
=======
32
33
33
34
@@ -142,7 +143,7 @@ $PSBoundParameters.GetEnumerator() | ForEach-Object { $ScriptParameters += ("-{0
142
143
$global :g_ScriptCommand = ' {0} {1}' -f $ScriptFullPath , $ ($ScriptParameters -join ' ' )
143
144
144
145
# Script Version
145
- $ScriptVersion = ' 2.6.0 '
146
+ $ScriptVersion = ' 2.6.1 '
146
147
147
148
# Set Log file path
148
149
$global :LOG_DATE = $ (Get-Date - Format yyyyMMdd) + ' -' + $ (Get-Date - Format HHmmss)
@@ -155,43 +156,40 @@ $global:UseVerboseFile = $UseVerboseFile.IsPresent
155
156
156
157
[hashtable ]$Global :BadAccountHashTable = @ {}
157
158
158
- # Global URLS
159
- # -----------
160
- $URL_PVWAAPI = $PVWAURL + ' /api'
161
- $URL_Authentication = $URL_PVWAAPI + ' /auth'
162
- $URL_Logon = $URL_Authentication + " /$AuthType /Logon"
163
- $URL_Logoff = $URL_Authentication + ' /Logoff'
164
159
165
- # URL Methods
166
- # -----------
167
- $URL_Safes = $URL_PVWAAPI + ' /Safes'
168
- $URL_SafeDetails = $URL_Safes + ' /{0}'
169
- $URL_SafeMembers = $URL_SafeDetails + ' /Members'
170
- $URL_Accounts = $URL_PVWAAPI + ' /Accounts'
171
- $URL_AccountsDetails = $URL_Accounts + ' /{0}'
172
- $URL_AccountsPassword = $URL_AccountsDetails + ' /Password/Update'
173
- $URL_PlatformDetails = $URL_PVWAAPI + ' /Platforms/{0}'
174
-
175
- # Script Defaults
176
- # ---------------
177
- $global :g_CsvDefaultPath = $Env: CSIDL_DEFAULT_DOWNLOADS
178
-
179
- # Safe Defaults
180
- # --------------
181
- $NumberOfDaysRetention = 7
182
- # $NumberOfVersionsRetention = 0
183
-
184
- # Template Safe parameters
185
- # ------------------------
186
- $TemplateSafeDetails = ' '
187
- $TemplateSafeMembers = ' '
160
+ # region Helper Functions
161
+ function Format-PVWAURL {
162
+ param (
163
+ [Parameter ()]
164
+ [string ]
165
+ $PVWAURL
166
+ )
167
+ # check url scheme to ensure it's secure and add https if not present
168
+ IF ($PVWAURL -match ' ^(?<scheme>https:\/\/|http:\/\/|).*$' ) {
169
+ if (' http://' -eq $matches [' scheme' ] -and $AllowInsecureURL -eq $false ) {
170
+ $PVWAURL = $PVWAURL.Replace (' http://' , ' https://' )
171
+ Write-LogMessage - type Warning - MSG " Detected inscure scheme in URL `n The URL was automaticly updated to: $PVWAURL `n Please ensure you are using the correct scheme in the url"
172
+ }
173
+ elseif ([string ]::IsNullOrEmpty($matches [' scheme' ])) {
174
+ $PVWAURL = " https://$PVWAURL "
175
+ Write-LogMessage - type Warning - MSG " Detected no scheme in URL `n The URL was automaticly updated to: $PVWAURL `n Please ensure you are using the correct scheme in the url"
176
+ }
177
+ }
188
178
189
- # Initialize Script Variables
190
- # ---------------------------
191
- $global :g_LogonHeader = ' '
192
- $global :g_LogAccountName = ' '
179
+ # check url for improper Privilege Cloud URL and add /PasswordVault/ if not present
180
+ if ($PVWAURL -match ' ^(?:https|http):\/\/(?<sub>.*).cyberark.(?<top>cloud|com)\/privilegecloud.*$' ) {
181
+ $PVWAURL = " https://$ ( $matches [' sub' ]) .privilegecloud.cyberark.$ ( $matches [' top' ]) /PasswordVault/"
182
+ Write-LogMessage - type Warning - MSG " Detected improperly formated Privilege Cloud URL `n The URL was automaticly updated to: $PVWAURL `n Please ensure you are using the correct URL. Pausing for 10 seconds to allow you to copy correct url.`n "
183
+ Start-Sleep 10
184
+ }
185
+ elseif ($PVWAURL -notmatch ' ^.*PasswordVault(?:\/|)$' ) {
186
+ $PVWAURL = " $PVWAURL /PasswordVault/"
187
+ Write-LogMessage - type Warning - MSG " Detected improperly formated Privileged Access Manager URL `n The URL was automaticly updated to: $PVWAURL `n Please ensure you are using the correct URL. Pausing for 10 seconds to allow you to copy correct url.`n "
188
+ Start-Sleep 10
189
+ }
190
+ return $PVWAURL
191
+ }
193
192
194
- # region Helper Functions
195
193
# @FUNCTION@ ======================================================================================================================
196
194
# Name...........: Test-CommandExists
197
195
# Description....: Tests if a command exists
@@ -215,10 +213,10 @@ The command to test
215
213
RETURN $true
216
214
}
217
215
}
218
- Catch {
216
+ catch {
219
217
Write-Host " $command does not exist" ; RETURN $false
220
218
}
221
- Finally {
219
+ Finally {
222
220
$ErrorActionPreference = $oldPreference
223
221
}
224
222
} # end function test-CommandExists
@@ -242,7 +240,7 @@ The text to encode
242
240
Write-LogMessage - type Debug - MSG " Returning URL Encode of $sText "
243
241
return [URI ]::EscapeDataString($sText )
244
242
}
245
- else {
243
+ else {
246
244
return $sText
247
245
}
248
246
}
@@ -270,10 +268,10 @@ The text to convert to bool (True / False)
270
268
if ($txt -match ' ^y$|^yes$' ) {
271
269
$retBool = $true
272
270
}
273
- elseif ($txt -match ' ^n$|^no$' ) {
271
+ elseif ($txt -match ' ^n$|^no$' ) {
274
272
$retBool = $false
275
273
}
276
- else {
274
+ else {
277
275
[bool ]::TryParse($txt , [ref ]$retBool ) | Out-Null
278
276
}
279
277
@@ -298,7 +296,7 @@ The text to handle
298
296
if ($null -ne $sText ) {
299
297
return $sText.Trim ()
300
298
}
301
- # Else
299
+ # else
302
300
return $sText
303
301
}
304
302
@@ -418,7 +416,7 @@ Creates a new Account Object
418
416
419
417
return $_Account
420
418
}
421
- catch {
419
+ catch {
422
420
Throw $ (New-Object System.Exception (' New-AccountObject: There was an error creating a new account object.' , $_.Exception ))
423
421
}
424
422
}
@@ -462,24 +460,24 @@ The Location to open the dialog in
462
460
Function Write-LogMessage {
463
461
<#
464
462
. SYNOPSIS
465
- Method to log a message on screen and in a log file
463
+ Method to log a message on screen and in a log file
466
464
467
465
. DESCRIPTION
468
- Logging The input Message to the Screen and the Log File.
469
- The Message Type is presented in colours on the screen based on the type
466
+ Logging The input Message to the Screen and the Log File.
467
+ The Message Type is presented in colours on the screen based on the type
470
468
471
469
. PARAMETER LogFile
472
- The Log File to write to. By default using the LOG_FILE_PATH
470
+ The Log File to write to. By default using the LOG_FILE_PATH
473
471
. PARAMETER MSG
474
- The message to log
472
+ The message to log
475
473
. PARAMETER Header
476
- Adding a header line before the message
474
+ Adding a header line before the message
477
475
. PARAMETER SubHeader
478
- Adding a Sub header line before the message
476
+ Adding a Sub header line before the message
479
477
. PARAMETER Footer
480
- Adding a footer line after the message
478
+ Adding a footer line after the message
481
479
. PARAMETER Type
482
- The type of the message to log (Info, Warning, Error, Debug)
480
+ The type of the message to log (Info, Warning, Error, Debug)
483
481
#>
484
482
param (
485
483
[Parameter (Mandatory = $true )]
@@ -753,7 +751,7 @@ The Header as Dictionary object
753
751
Throw $PSItem.Exception
754
752
}
755
753
Else {
756
- Write-LogMessage - type Verbose - MSG " Invoke-Rest:`t Error in running $Command on '$URI ', $ ( $ ($Details.Details.ErrorMessage ) -Join " ; " ) "
754
+ Write-LogMessage - type Verbose - MSG " Invoke-Rest:`t Error in running $Command on '$URI ', $ ( $ ($Details.Details.ErrorMessage ) -Join ' ; ' ) "
757
755
Write-LogMessage - type Verbose - MSG " Invoke-Rest:`t $ ( $Details.Details.ErrorMessage ) "
758
756
Throw $ ($Details.Details.ErrorMessage )
759
757
}
@@ -795,7 +793,7 @@ The Safe Name to return
795
793
$accSafeURL = $URL_SafeDetails -f $ (ConvertTo-URL $safeName )
796
794
$_safe = $ (Invoke-Rest - Uri $accSafeURL - Header $g_LogonHeader - Command ' Get' - ErrAction $ErrAction )
797
795
}
798
- catch {
796
+ catch {
799
797
Write-LogMessage - type Error - MSG " Error getting Safe '$safeName ' details. Error: $ ( $ ($ ($_.ErrorDetails.Message ) | ConvertFrom-Json ).ErrorMessage) "
800
798
}
801
799
@@ -936,7 +934,7 @@ The Safe Name to return its Members
936
934
$_retSafeOwners += $item
937
935
}
938
936
}
939
- catch {
937
+ catch {
940
938
Write-LogMessage - type Error - MSG " Error getting Safe '$safeName ' members. Error: $ ( Join-ExceptionMessage $_.Exception ) "
941
939
}
942
940
@@ -976,7 +974,7 @@ The Safe Name check if exists
976
974
return $true
977
975
}
978
976
}
979
- catch {
977
+ catch {
980
978
Write-LogMessage - type Error - MSG " Error testing safe '$safeName ' existence. Error: $ ( Join-ExceptionMessage $_.Exception ) " - ErrorAction ' SilentlyContinue'
981
979
}
982
980
}
@@ -1018,7 +1016,7 @@ The Template Safe object (returned from the Get-Safe method). If entered the new
1018
1016
$templateSafeObject.SafeName = $safeName
1019
1017
$restBody = $templateSafeObject | ConvertTo-Json - Depth 3 - Compress
1020
1018
}
1021
- else {
1019
+ else {
1022
1020
# Create the Target Safe
1023
1021
Write-LogMessage - type Info - MSG " Creating Safe $safeName "
1024
1022
$bodySafe = @ { SafeName = $safeName ; Description = " $safeName - Created using Accounts Onboard Utility" ; OLACEnabled = $false ; ManagingCPM = $cpmName ; NumberOfDaysRetention = $NumberOfDaysRetention }
@@ -1058,12 +1056,12 @@ Outputs the bad record to a CSV file for correction and processing
1058
1056
. DESCRIPTION
1059
1057
Outputs the bad record to a CSV file for correction and processing
1060
1058
#>
1061
- [CmdletBinding ()]
1062
- param (
1063
- [Parameter ()]
1064
- [string ]
1065
- $ErrorMessage
1066
- )
1059
+ [CmdletBinding ()]
1060
+ param (
1061
+ [Parameter ()]
1062
+ [string ]
1063
+ $ErrorMessage
1064
+ )
1067
1065
Try {
1068
1066
1069
1067
If ($null -ne $ErrorMessage ) {
@@ -1124,7 +1122,7 @@ The Good record to output
1124
1122
Write-LogMessage - type Debug - MSG ' Outputted good record to CSV'
1125
1123
Write-LogMessage - type Verbose - MSG " Good Record:`t $global :workAccount "
1126
1124
}
1127
- catch {
1125
+ catch {
1128
1126
Write-LogMessage - type Error - MSG " Unable to output good record to file: $csvPathGood "
1129
1127
Write-LogMessage - type Verbose - MSG " Good Record:`t $global :workAccount "
1130
1128
@@ -1280,7 +1278,7 @@ The Account Safe Name to search in
1280
1278
throw " Found $ ( $_retAccount.count ) accounts in search - fix duplications"
1281
1279
}
1282
1280
}
1283
- catch {
1281
+ catch {
1284
1282
Throw $ (New-Object System.Exception (' Get-Account: Error getting Account.' , $_.Exception ))
1285
1283
}
1286
1284
@@ -1332,7 +1330,7 @@ The Account Safe Name to search in
1332
1330
return $true
1333
1331
}
1334
1332
}
1335
- catch {
1333
+ catch {
1336
1334
Write-LogMessage - type Error - MSG " Error testing Account '$g_LogAccountName ' existence. Error: $ ( Join-ExceptionMessage $_.Exception ) " - ErrorAction ' SilentlyContinue'
1337
1335
}
1338
1336
}
@@ -1377,7 +1375,7 @@ The property to check in the platform
1377
1375
Throw ' Platform does not exist or we had an issue'
1378
1376
}
1379
1377
}
1380
- catch {
1378
+ catch {
1381
1379
Write-LogMessage - type Error - MSG " Error checking platform properties. Error: $ ( Join-ExceptionMessage $_.Exception ) "
1382
1380
}
1383
1381
@@ -1412,7 +1410,7 @@ The REST API Credentials to authenticate
1412
1410
If ($concurrentSession ) {
1413
1411
$logonBody = @ { username = $Credentials.username.Replace (' \' , ' ' ); password = $Credentials.GetNetworkCredential ().password; concurrentSession = ' true' } | ConvertTo-Json - Compress
1414
1412
}
1415
- else {
1413
+ else {
1416
1414
$logonBody = @ { username = $Credentials.username.Replace (' \' , ' ' ); password = $Credentials.GetNetworkCredential ().password } | ConvertTo-Json - Compress
1417
1415
}
1418
1416
If (! [string ]::IsNullOrEmpty($RadiusOTP )) {
@@ -1425,7 +1423,7 @@ The REST API Credentials to authenticate
1425
1423
# Clear logon body
1426
1424
$logonBody = ' '
1427
1425
}
1428
- catch {
1426
+ catch {
1429
1427
Throw $ (New-Object System.Exception (" Get-LogonHeader: $ ( $_.Exception.Response.StatusDescription ) " , $_.Exception ))
1430
1428
}
1431
1429
@@ -1467,7 +1465,7 @@ Tests if the script is running the latest version
1467
1465
try {
1468
1466
$getScriptContent = (Invoke-WebRequest - UseBasicParsing - Uri $scriptURL ).Content
1469
1467
}
1470
- catch {
1468
+ catch {
1471
1469
Throw $ (New-Object System.Exception (" Test-LatestVersion: Couldn't download and check for latest version" , $_.Exception ))
1472
1470
}
1473
1471
If ($ ($getScriptContent -match ' ScriptVersion\s{0,1}=\s{0,1}\"([\d\.]{1,5})\"' )) {
@@ -1497,6 +1495,44 @@ Tests if the script is running the latest version
1497
1495
1498
1496
# endregion
1499
1497
1498
+
1499
+ # Global URLS
1500
+ # -----------
1501
+ $URL_PVWAURL = Format-PVWAURL ($PVWAURL )
1502
+ $URL_PVWAAPI = $URL_PVWAURL + ' /api'
1503
+ $URL_Authentication = $URL_PVWAAPI + ' /auth'
1504
+ $URL_Logon = $URL_Authentication + " /$AuthType /Logon"
1505
+ $URL_Logoff = $URL_Authentication + ' /Logoff'
1506
+
1507
+ # URL Methods
1508
+ # -----------
1509
+ $URL_Safes = $URL_PVWAAPI + ' /Safes'
1510
+ $URL_SafeDetails = $URL_Safes + ' /{0}'
1511
+ $URL_SafeMembers = $URL_SafeDetails + ' /Members'
1512
+ $URL_Accounts = $URL_PVWAAPI + ' /Accounts'
1513
+ $URL_AccountsDetails = $URL_Accounts + ' /{0}'
1514
+ $URL_AccountsPassword = $URL_AccountsDetails + ' /Password/Update'
1515
+ $URL_PlatformDetails = $URL_PVWAAPI + ' /Platforms/{0}'
1516
+
1517
+ # Script Defaults
1518
+ # ---------------
1519
+ $global :g_CsvDefaultPath = $Env: CSIDL_DEFAULT_DOWNLOADS
1520
+
1521
+ # Safe Defaults
1522
+ # --------------
1523
+ $NumberOfDaysRetention = 7
1524
+ # $NumberOfVersionsRetention = 0
1525
+
1526
+ # Template Safe parameters
1527
+ # ------------------------
1528
+ $TemplateSafeDetails = ' '
1529
+ $TemplateSafeMembers = ' '
1530
+
1531
+ # Initialize Script Variables
1532
+ # ---------------------------
1533
+ $global :g_LogonHeader = ' '
1534
+ $global :g_LogAccountName = ' '
1535
+
1500
1536
# Write the entire script command when running in Verbose mode
1501
1537
Write-LogMessage - type Verbose - MSG " Base:`t $g_ScriptCommand "
1502
1538
# Header
@@ -1514,7 +1550,7 @@ If ($DisableSSLVerify) {
1514
1550
# Disable SSL Verification
1515
1551
[System.Net.ServicePointManager ]::ServerCertificateValidationCallback = { $DisableSSLVerify }
1516
1552
}
1517
- catch {
1553
+ catch {
1518
1554
Write-LogMessage - type Error - MSG ' Could not change SSL validation'
1519
1555
Write-LogMessage - type Error - MSG (Join-ExceptionMessage $_.Exception ) - ErrorAction ' SilentlyContinue'
1520
1556
return
@@ -1525,7 +1561,7 @@ Else {
1525
1561
Write-LogMessage - type Debug - MSG ' Setting script to use TLS 1.2'
1526
1562
[System.Net.ServicePointManager ]::SecurityProtocol = [System.Net.SecurityProtocolType ]::Tls12
1527
1563
}
1528
- catch {
1564
+ catch {
1529
1565
Write-LogMessage - type Error - MSG ' Could not change SSL settings to use TLS 1.2'
1530
1566
Write-LogMessage - type Error - MSG (Join-ExceptionMessage $_.Exception ) - ErrorAction ' SilentlyContinue'
1531
1567
}
@@ -1663,7 +1699,7 @@ $csvPathBad = "$csvPath.bad.csv"
1663
1699
Remove-Item $csvPathBad - Force - ErrorAction SilentlyContinue
1664
1700
1665
1701
$accountsCSV = Import-Csv $csvPath - Delimiter $delimiter
1666
- $accountsCSV = $accountsCSV | Select-Object - ExcludeProperty ErrorMessage
1702
+ $accountsCSV = $accountsCSV | Select-Object - ExcludeProperty ErrorMessage
1667
1703
$rowCount = $ ($accountsCSV.Safe.Count )
1668
1704
$counter = 0
1669
1705
0 commit comments