{"id":934,"date":"2019-12-23T08:46:07","date_gmt":"2019-12-23T07:46:07","guid":{"rendered":"http:\/\/www.vatland.no\/?p=934"},"modified":"2019-12-27T06:27:08","modified_gmt":"2019-12-27T05:27:08","slug":"simple-powershell-mru-list","status":"publish","type":"post","link":"https:\/\/www.vatland.no\/index.php\/simple-powershell-mru-list\/","title":{"rendered":"Simple Powershell MRU list"},"content":{"rendered":"<p>When using using my secret server powershell functions I got tired of constantly searching for secret ID&#8217;s. I had to do a new search just because I could not remember the ID&#8217;s. So I added some kind of MRU to my get-secretID function. This code block creates to classes mruitem and mrulist. The mrulist has three functions. Updatelist: Check if the ID already is in the list , if so update last used time. If it is not in the list , add it. Also remove oldest item if list is longer then max size. Savelist: saves the list to mru file. Loadlist : Load old list from file. Script also uses a global variable name ssmru. The global variable is declared in the powershell profile as $ssmru = &#8220;&lt;filepath to mru list&gt;&#8221;. I use a file because I want this MRU to stay persistent during a reboot.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\r\n# MRU list and item class \r\nclass mruitem{\r\n&#x5B;string]$ssid\r\n&#x5B;string]$name\r\n&#x5B;datetime]$lastuseddate\r\n\r\nmruitem(&#x5B;string]$ssid,&#x5B;string]$name,&#x5B;datetime]$lastuseddate)\r\n{\r\n$this.ssid=$ssid\r\n$this.lastuseddate=$lastuseddate\r\n$this.name=$name\r\n}\r\n}\r\n\r\nclass mrulist: System.Collections.ArrayList {\r\n\r\n&#x5B;int]$MaxSize = 15\r\n\r\nupdatelist(&#x5B;mruitem]$item){\r\n$pos=$null\r\nif($this.count -gt 0){\r\nif($this.ssid.contains($item.ssid)){\r\n$pos=$this.ssid.indexof($item.ssid)\r\n}\r\nelse {$pos=$null}\r\n\r\nif($pos){\r\n$this&#x5B;$pos].lastuseddate=$item.lastuseddate\r\n$this&#x5B;$pos].name=$item.name\r\n}else{ #Add new\r\n$this.add($item)\r\n}\r\n}else {\r\n$this.add($item)\r\n}\r\nif($this.count -gt $this.MaxSize){\r\n#delete oldest\r\n$new = New-Object System.Collections.ArrayList\r\n$new=($this| Sort-Object -Property lastuseddate )\r\n$ssid=$new&#x5B;0].ssid\r\n$ssid\r\n$pos=$this.ssid.indexof($ssid)\r\n$this.RemoveAt($pos)\r\n$new=$null\r\n}\r\n}\r\n\r\nloadlist(){\r\nif(Test-Path $global:ssmru){\r\n$data=(Get-Content -Path $global:ssmru -Encoding Unicode)|ConvertFrom-Json\r\nforeach($mru in $data){\r\n$this.updatelist(&#x5B;mruitem]::new($mru.ssid,$mru.name,$mru.lastuseddate))\r\n}\r\n}\r\n}\r\n\r\nsavelist(){\r\n$data=$this|ConvertTo-Json\r\n$data|out-file -FilePath $global:ssmru -Encoding unicode\r\n}\r\n}\r\n\r\n$mrulist=New-Object -typename mrulist\r\n$mrulist.loadlist()\r\nif($mru){\r\n$mrulist | Sort-Object -Property lastuseddate\r\nreturn\r\n}\r\n<\/pre>\n<p>For those interested , here is the updated version of get-secretID<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\r\nfunction Get-SecretID\r\n{\r\nparam(\r\n&#x5B;parameter(ValueFromPipeline=$True)]\r\n&#x5B;int] $secretID,\r\n&#x5B;pscredential]$sscred,\r\n&#x5B;switch]$Cleartext,\r\n&#x5B;switch]$mru\r\n)\r\nif(!($secretID)){$mru=$true}\r\n\r\n# MRU list and item class\r\nclass mruitem{\r\n&#x5B;string]$ssid\r\n&#x5B;string]$name\r\n&#x5B;datetime]$lastuseddate\r\n\r\nmruitem(&#x5B;string]$ssid,&#x5B;string]$name,&#x5B;datetime]$lastuseddate)\r\n{\r\n$this.ssid=$ssid\r\n$this.lastuseddate=$lastuseddate\r\n$this.name=$name\r\n}\r\n}\r\n\r\nclass mrulist: System.Collections.ArrayList {\r\n\r\n&#x5B;int]$MaxSize = 15\r\n\r\nupdatelist(&#x5B;mruitem]$item){\r\n$pos=$null\r\nif($this.count -gt 0){\r\nif($this.ssid.contains($item.ssid)){\r\n$pos=$this.ssid.indexof($item.ssid)\r\n}\r\nelse {$pos=$null}\r\n\r\nif($pos){\r\n$this&#x5B;$pos].lastuseddate=$item.lastuseddate\r\n$this&#x5B;$pos].name=$item.name\r\n}else{ #Add new\r\n$this.add($item)\r\n}\r\n}else {\r\n$this.add($item)\r\n}\r\nif($this.count -gt $this.MaxSize){\r\n#delete oldest\r\n$new = New-Object System.Collections.ArrayList\r\n$new=($this| Sort-Object -Property lastuseddate )\r\n$ssid=$new&#x5B;0].ssid\r\n$ssid\r\n$pos=$this.ssid.indexof($ssid)\r\n$this.RemoveAt($pos)\r\n$new=$null\r\n}\r\n}\r\n\r\nloadlist(){\r\nif(Test-Path $global:ssmru){\r\n$data=(Get-Content -Path $global:ssmru -Encoding Unicode)|ConvertFrom-Json\r\nforeach($mru in $data){\r\n$this.updatelist(&#x5B;mruitem]::new($mru.ssid,$mru.name,$mru.lastuseddate))\r\n}\r\n}\r\n}\r\n\r\nsavelist(){\r\n$data=$this|ConvertTo-Json\r\n$data|out-file -FilePath $global:ssmru -Encoding unicode\r\n}\r\n}\r\n\r\n$mrulist=New-Object -typename mrulist\r\n$mrulist.loadlist()\r\nif($mru){\r\n$mrulist | Sort-Object -Property lastuseddate\r\nreturn\r\n}\r\n\r\n$where = 'https:\/\/&lt;Server FQDN&gt;\/secretserver\/winauthwebservices\/sswinauthwebservice.asmx'\r\n\r\nif($sscred -ne $null){\r\ntry{\r\n$ws = New-WebServiceProxy -uri $where -Credential $sscred\r\n}\r\ncatch{\r\nWrite-host &quot;Error: Error connecting to secret server.&quot;\r\nreturn $null\r\n}\r\n}else{\r\n\r\ntry{\r\n$ws = New-WebServiceProxy -uri $where -UseDefaultCredential -ErrorAction SilentlyContinue\r\nif($ws -eq $null){\r\nif (!(Test-Path Variable:\\ssadmin)){\r\nthrow {\r\nWrite-host &quot;No secretserver admin specified or variable 'ssadmin' defined.`nThis is to be used by 'get-storedcredential'&quot;\r\n}\r\n}\r\n$adminacc=Get-StoredCredential -UserName $ssadmin\r\n$ws = New-WebServiceProxy -uri $where -Credential $adminacc -ErrorAction SilentlyContinue\r\nif($ws -eq $null){throw{Write-host &quot;Unable to connect to SecretServer&quot;}}\r\n}\r\n}\r\ncatch{\r\nWrite-host &quot;Error connecting to SecretServer&quot;\r\nreturn $null\r\n}\r\n}\r\n\r\n$wsResult = $ws.GetSecret($secretId, $false, $null)\r\nif($wsresult.errors -ne $null){\r\n$Cred=New-Object PSObject\r\n$Cred | add-member -NotePropertyName &quot;Username&quot; -NotePropertyValue $wsresult.errors\r\n$Cred | Add-Member -NotePropertyName &quot;Password&quot; -NotePropertyValue $wsresult.errors\r\n\r\nreturn $Cred\r\n} else {\r\n\r\n$u=$wsResult.Secret.Items&#x5B;1].value.ToString()\r\n$ep = ConvertTo-SecureString $wsResult.Secret.Items&#x5B;2].value.ToString() -AsPlainText -Force\r\n&#x5B;pscredential]$Cred = New-Object -TypeName &quot;System.Management.Automation.PSCredential&quot; -ArgumentList $u,$ep\r\nif($Cleartext){\r\n&#x5B;psobject]$Cred=New-Object PSObject\r\n$Cred | add-member -NotePropertyName &quot;Username&quot; -NotePropertyValue $u\r\n$Cred | Add-Member -NotePropertyName &quot;Password&quot; -NotePropertyValue $wsResult.Secret.Items&#x5B;2].value.ToString()\r\n$Cred | Add-Member -NotePropertyName &quot;Domain&quot; -NotePropertyValue $wsResult.Secret.Items&#x5B;0].value.ToString()\r\n}\r\n$mrulist.updatelist(&#x5B;mruitem]::new($secretID,$u,(get-date)))\r\n$mrulist.savelist()\r\nreturn $Cred\r\n}\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>When using using my secret server powershell functions I got tired of constantly searching for secret ID&#8217;s. I had to do a new search just because I could not remember the ID&#8217;s. So I added some kind of MRU to my get-secretID function. This code block creates to classes mruitem and mrulist. The mrulist has &hellip; <a href=\"https:\/\/www.vatland.no\/index.php\/simple-powershell-mru-list\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Simple Powershell MRU list<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Simple Powershell MRU list","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[48],"tags":[88,89,90,59,85],"class_list":["post-934","post","type-post","status-publish","format-standard","hentry","category-powershell","tag-classes","tag-collections","tag-mru","tag-powershell","tag-secretserver"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":false,"jetpack-related-posts":[{"id":875,"url":"https:\/\/www.vatland.no\/index.php\/csp-access-to-tenants-using-powershell-part-1\/","url_meta":{"origin":934,"position":0},"title":"CSP access to tenants using powershell. Part 1","author":"Atle","date":"September 18, 2019","format":false,"excerpt":"A short explanation of how to access customer tenant using a CSP tenant SPN credential connectiong to AzureAD and AZ. Have been struggling for a while to manage all our customers tenants using powershell scripts. It can be complicated to organize all the credentials, tenant domain, tenant id's password expiry.\u2026","rel":"","context":"In &quot;Azure&quot;","block_context":{"text":"Azure","link":"https:\/\/www.vatland.no\/index.php\/category\/azure\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1146,"url":"https:\/\/www.vatland.no\/index.php\/list-nordpool-electric-prices-using-powershell\/","url_meta":{"origin":934,"position":1},"title":"List NordPool electric prices using powershell.","author":"Atle","date":"January 10, 2022","format":false,"excerpt":"This is a small script using nordpoolgroup api to get todays electric prices for Kr.sand - Norway. This is the same API as their webpage uses. All the urls and parameters can be found using developermode in the browser. This code is only to demonstrate that it can be done.\u2026","rel":"","context":"In \"Api\"","block_context":{"text":"Api","link":"https:\/\/www.vatland.no\/index.php\/tag\/api\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":957,"url":"https:\/\/www.vatland.no\/index.php\/hash-tables-in-powershell\/","url_meta":{"origin":934,"position":2},"title":"Hash tables in powershell","author":"Atle","date":"March 23, 2020","format":false,"excerpt":"We all have the need to store data in some kind of arrays. I use hashtables a lot. Preferred use is as a lookup table, I can use 'contains' instead of looping through each item or reference an object by name instead of index number. Lookup table for licenses is\u2026","rel":"","context":"In &quot;CSP&quot;","block_context":{"text":"CSP","link":"https:\/\/www.vatland.no\/index.php\/category\/csp\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":765,"url":"https:\/\/www.vatland.no\/index.php\/list-exchange-mailboxes-with-forwarding-rules\/","url_meta":{"origin":934,"position":3},"title":"List Exchange mailboxes with forwarding rules","author":"Atle","date":"May 4, 2018","format":false,"excerpt":"Simple list of all mailboxes and rules. Displays more info if one of them contains a forwarding rule: [powershell]$mb=Get-Mailbox | Sort-Object -Property displayname $t2=0;$t=($mb).count;$mb| ForEach-Object {write-host $t2\"\\\"$t \" \" $_.displayname;$t2++;get-inboxrule -mailbox $_.alias| ForEach-Object {if($_.description -like \"*forward*\"){write-host $_.description -foregroundcolor red}}}[\/powershell]","rel":"","context":"In &quot;Exchange&quot;","block_context":{"text":"Exchange","link":"https:\/\/www.vatland.no\/index.php\/category\/exchange\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":804,"url":"https:\/\/www.vatland.no\/index.php\/use-powershell-to-get-leakedcredentials-from-azure-using-graph\/","url_meta":{"origin":934,"position":4},"title":"Use Powershell to get LeakedCredentials from Azure using Graph","author":"Atle","date":"November 1, 2018","format":false,"excerpt":"Leaked credentials listed from Azure using powershell and Microsoft Graph\u00a0We need one Azure AD Premium X license to get this log. Would it be nice to list all leakedcredentials using powershell?(or riskysignins or identiyriskevents). All of this could be achieved using powershell and REST api at Microsoft Graph. I have\u2026","rel":"","context":"In \"Powershell\"","block_context":{"text":"Powershell","link":"https:\/\/www.vatland.no\/index.php\/tag\/powershell\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.vatland.no\/wp-content\/uploads\/2018\/11\/Leaked.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.vatland.no\/wp-content\/uploads\/2018\/11\/Leaked.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.vatland.no\/wp-content\/uploads\/2018\/11\/Leaked.jpg?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":21,"url":"https:\/\/www.vatland.no\/index.php\/list-members-of-dynamic-groups-show-incorrect-members\/","url_meta":{"origin":934,"position":5},"title":"List members of dynamic groups show incorrect members.","author":"Atle","date":"January 23, 2014","format":false,"excerpt":"If you use PowerShell to list members of dynamic distribution Groups in Exchange 2013 you would probably see more entries than expected. The PowerShell commands $dgr=Get-DynamicDistributionGroup \"GroupNAme\"Get-Recipient -RecipientPreviewFilter $dgr.RecipientFilterdoes not take in to consideration OU filtering. If you look at $dgr.RecipientFiler it only contains the other attributes.I do not know\u2026","rel":"","context":"In &quot;Categories&quot;","block_context":{"text":"Categories","link":"https:\/\/www.vatland.no\/index.php\/category\/categories\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts\/934","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/comments?post=934"}],"version-history":[{"count":10,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts\/934\/revisions"}],"predecessor-version":[{"id":944,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts\/934\/revisions\/944"}],"wp:attachment":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/media?parent=934"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/categories?post=934"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/tags?post=934"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}