というわけで、PowerShellで チームを一括作成できるか
調査してみました。
まず、Microsoft TeamsはOffice365グループと連動しています。
さらに、Office365グループを動的メンバーシップにすることで
Teams側でも動的更新できるみたいです。
チームの動的なメンバーシップの概要 - Microsoft Docs
https://docs.microsoft.com/ja-jp/microsoftteams/dynamic-memberships
チームの動的なメンバーシップの概要 - Microsoft Docs
https://docs.microsoft.com/ja-jp/microsoftteams/dynamic-memberships
#レジストリプロパティを入力、時間を出力
function convtime($x) {
$LittleEndianTime=$x[60..67] | % { $_.tostring("x2") }
$BigEndianTime=$null
$($LittleEndianTime.count-1)..0 | % { $BigEndianTime += $LittleEndianTime[$_] }
$filetime=[convert]::ToInt64("$BigEndianTime", 16)
[datetime]::fromfiletime($filetime)
}
#オブジェクトに各データを入れデータ格納
$result = $iname | % {
$count = $iProp.$_[4]
if ($count -ne 0){
$output = New-Object psobject
$output | Add-Member noteproperty pcount $iProp.$_[4]
$output | Add-Member noteproperty pname $(func $_)
$output | Add-Member noteproperty ptime $(convtime $iprop.$_)
$output
}
}
#お好みでオブジェクト整形
$result | sort-Object -Property ptime -Descending
$iName | %{
$count = $iProp.$_[4]
if ($count -ne 0){
"{0}回 {1}" -f $count, (func $_)
}
}
![]() |
| レジストリエディターでキーをみたところ |
![]() |
| 実際に実行してみたところ。回数とプログラムが出力される |
Function Get-Data {
Param($date)
if ($WebClient -eq $null) {
$Global:WebClient=new-object System.Net.WebClient
}
$results=$webClient.DownloadString("http://denki.cuppat.net/data/$($date).json")
$Results -match """hours"":\[(?<hour>.*)].*""capability""\:(?<cap>.*)," > $null
$matches
}
Function Check-Data {
Param($getdata)
$Ltime = $getdata.hour -split ","
$cap=$getdata.cap
write-host キャパシティ $cap
0..$(($Ltime.length)-1)|% {
$p=$ltime[$_]/$cap
if ($p -ge 0.95) {
$colorname="red"
}elseif ($p -ge 0.90) {
$colorname="darkyellow"
}else {
$colorname="black"
}
$a="{0:00}時:電力{1} {2:00}% {3}{4}|" -F $_,$ltime[$_],$($p*100),$("#"*$($p*50)),$(" "*(50-$($p*50)))
write-host $a -ForegroundColor $colorname
}
}
$tdata=Get-Data($(get-date -uformat "%Y%m%d"))
$ydata=Get-Data($(get-date -uformat "%Y%m%d")-1)
check-data($ydata)
check-data($tdata)
Function Get-TwitterSearch {
Param($searchTerm)
if ($WebClient -eq $null) {
$Global:WebClient=new-object System.Net.WebClient
}
$results=[xml]($webClient.DownloadString("http://search.twitter.com/search.atom?lang=ja&q=$SearchTerm"))
$Searchitems=$results.feed.entry
$SearchItems
}
$tdata= Get-TwitterSearch PowerShell
$tdata | %{ write-host $_.author.name "--" $([datetime]$_.published); write-host $_.title; write-host }
$writeDir="\\buso-pcv\test"
$writeTxt="usblog.txt"
$tmpColor= @("Red", "Blue", "Green", "Magenta", "DarkCyan")
[Void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$i = 0 #終了フラグ
$cl = 0 #カラーバリエーション
$watcher = New-Object System.IO.FileSystemWatcher # FileSystemWatcherの作成
$watcher.Path = $writeDir # 監視対象のフォルダ指定
$watcher.Filter = $writeTxt # フィルター
$watcher.NotifyFilter = [System.IO.NotifyFilters]::LastWrite
$NotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$powerShellExe = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$icon = [System.Drawing.Icon]::ExtractAssociatedIcon($powerShellExe)
$notifyIcon.Icon = $icon
$notifyIcon.Visible = $true
Write-Host "チェック開始します。"
while ($i -ge 0)
{
$result = $watcher.WaitForChanged([System.IO.WatcherChangeTypes]::ALL)
$tmpVar = $(Get-Content "$writeDir\$writeTxt")[-1] -split ","
Write-Host ""
Write-Host "#########################################"
Write-host "【コンピュータ】" $tmpVar[0] -ForegroundColor $tmpColor[$cl]
Write-host "【ユーザー】" $tmpVar[1] -ForegroundColor $tmpColor[$cl]
Write-host "【ログオフ時刻】" $tmpVar[2] -ForegroundColor $tmpColor[$cl]
Write-Host "#########################################"
$notifyIcon.ShowBalloonTip("1", "USBチェック", "USBメモリがささっているユーザーがいます", "Info")
$cl+=1
if ($cl -eq $tmpColor.length) {
$cl=0
}
}| 出力ごとに色が変わり、バルーンも出力 |
Get-WmiObject -Class win32_usbhub | ? { $_.name -eq "USB 大容量記憶装置" } | ? { $_.status -eq "OK" }| USBメモリをさしていた場合 |
#USBログオフ時メッセージプロンプト処理
#メッセージ文
$messagePath="C:\temp\usbmessage.txt"
#ログ出力パス
$usbLOG="\\buso-pcv\test\usblog.txt"
#--------------------------------------
#メッセージボックス
#--------------------------------------
function MessageBox([string]$p_value = "")
{
[Void][Windows.Forms.MessageBox]::Show($p_value,"お知らせ","OK", "Warning")
}
$crUSB = Get-WmiObject -Class win32_usbhub | ? { $_.name -eq "USB 大容量記憶装置" } | ? { $_.status -eq "OK" }
if ($crUSB) {
write-output "$env:computername,$env:username,$(get-date)" >> $usbLOG
#Windowsフォームのロード
[Void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms");
MessageBox $([String]::Join("`r`n", (Get-Content $messagePath)))
}
メッセージ文は、いろんな人が編集する場所でもあることから、USBがさしっぱなしだぞー( ゚Д゚)また、ダイヤログが出たときに、使用者のホスト名、ユーザー名、時刻を吐き出すようにしてみました。
誰かに盗まれても知らないぞ( ´∀`)
って、席にもういないッッΣΣ(゚Д゚;)
| USB差しっぱなしでログオフした場合 |
| usblogに記録されたログ |
| GPOによるスクリプト実行ポリシーの許可 |
| ログオフスクリプトのPowerShellタブ |
| USBメモリさし忘れ監視 |
$null = [Reflection.Assembly]::LoadWithPartialName("System.Speech")
$SMSpeaker = new-object System.Speech.Synthesis.SpeechSynthesizer
$SMSpeaker.Speak("hello buso")日本語はデフォでは対応していないらしく、Office2003についてくるLH Kenj なんかの音声合成エンジンを使わなければならないっぽい。
#CheckGPO
Import-Module activedirectory
Import-Module grouppolicy
#origpoファイルの場所
$workpath="C:\hogehoge\"
#メール配信先設定
$smtpHost = "SMTPサーバアドレス"
$mailfrom = "FROMのアドレス"
$mailto = "メール配信先"
$mailsubject = "GPOCheckログ"
$mailer = New-Object System.net.mail.smtpclient($smtpHost)
function comparegpo ($crlink, $orilink, $crgpo, $origpo) {
#gpo設定 変更された場合は新しいGPOのバックアップを行い oriファイルを更新
compare-object $crgpo $origpo -property modificationtime,gpostatus,displayname | Set-Variable diffgpo
if ($diffgpo) {
"$(get-date) :--GPO変更が発生しました"
$diffgpo | sort displayname | ft -AutoSize
$timename=$(Get-ItemProperty $workpath\origpo.xml).LastWriteTime -replace "[/,:, ]",""
$diffgpo | ? { $_.sideindicator -eq "<=" } | % { "backup実施"; backup-gpo $_.displayname -path $workpath\gpbackup | fl }
move-item $workpath\origpo.xml $workpath\log\$timename"gpo.xml" | Out-null
$crgpo | Export-Clixml $workpath\origpo.xml
}
#link設定 変更された場合は oriファイルを更新
compare-object $crlink $orilink -Property target,displayname,enabled | Set-Variable diffgpl
if ($diffgpl) {
"$(get-date) :--GPO Linkに増減が発生しました"
$diffgpl | sort displayname | ft -AutoSize
$timename=$(Get-ItemProperty $workpath\orilink.xml).LastWriteTime -replace "[/,:, ]",""
move-item $workpath\orilink.xml $workpath\log\$timename"orilink.xml"
$crlink | Export-Clixml $workpath\orilink.xml
}
}
#origpo存在チェック
if (test-path "$workpath\origpo.xml"){
$origpo=Import-Clixml "$workpath\origpo.xml"
} else {
"origpo.xml NotFound"
get-gpo -all | Export-Clixml $workpath\origpo.xml
return
}
if (test-path "$workpath\orilink.xml"){
$orilink=Import-Clixml "$workpath\orilink.xml"
} else {
"orilink.xml NotFound"
Get-ADOrganizationalUnit -Filter 'Name -like "*"' | % { Get-GPInheritance -Target $_ } | ? { $_.gpolinks -ne "" } | % { $_.path; $_.gpolinks } | Export-Clixml $workpath\orilink.xml
return
}
#現在のOU状態の取得
$crlink = Get-ADOrganizationalUnit -Filter 'Name -like "*"' | % { Get-GPInheritance -Target $_ } | ? { $_.gpolinks -ne "" } | % { $_.path; $_.gpolinks }
$crgpo = get-gpo -all
#比較対象を関数で渡し、戻り値が存在した場合にはメールを出す
$result=comparegpo $crlink $orilink $crgpo $origpo
if ($result) {
$mailbody=[string]::join("`r`n", ($result | out-string -width 200 ))
$mailer.send($mailfrom, $mailto, $mailsubject, $mailbody )
$result | out-string -width 200 > $workpath\recent.log
$result
"変更が発生し、メールを出しました"
}
$work フォルダの配下にlog フォルダと、 gpbackupフォルダを用意してください。PS > Import-Module grouppolicy
PS > get-gpo -all
PS > Get-GPO -All | Export-Clixml -Path .\origpo.xmlでは、試しにGPOを変更して、比較してみましょう。
PS > $origpo=Import-Clixml .\origpo.xml
PS > $crgpo=Get-GPO -All
PS > Compare-Object $crgpo $origpo -Property displayname,modificationtime,GpoStatus | sort displayname
PS > Import-Module activedirectoryこれにより、ADやグループポリシーに関するコマンドを使用することができます。
PS > Import-Module grouppolicy
PS> Get-Command -module activedirectory
CommandType Name Definition
----------- ---- ----------
Cmdlet Add-ADComputerServiceAccount Add-ADComputerServiceAccount...
Cmdlet Add-ADDomainControllerPasswo... Add-ADDomainControllerPasswo...
Cmdlet Add-ADFineGrainedPasswordPol... Add-ADFineGrainedPasswordPol...
Cmdlet Add-ADGroupMember Add-ADGroupMember [-Identity...
Cmdlet Add-ADPrincipalGroupMembership Add-ADPrincipalGroupMembersh...
:
PS > Get-Command -module grouppolicyさて、では例として下記のようにGPOがリンクされていた場合。
CommandType Name Definition
----------- ---- ----------
Cmdlet Backup-GPO Backup-GPO -Guid-Pat...
Cmdlet Copy-GPO Copy-GPO -SourceGuid...
Cmdlet Get-GPInheritance Get-GPInheritance [-Target] ...
Cmdlet Get-GPO Get-GPO [-Guid][[-Do...
Cmdlet Get-GPOReport Get-GPOReport [-Guid]...
PS> Get-GPInheritance -target "OU=GroupA,OU=UserList,DC=furyu,DC=local"ちょっとこれだけだとわかりづらいから、 GpoLinks だけを取り出してみる。
Name : groupa
ContainerType : OU
Path : ou=groupa,ou=userlist,dc=furyu,dc=local
GpoInheritanceBlocked : No
GpoLinks : {GPOtest1, GPOtest2}
InheritedGpoLinks : {GPOtest1, GPOtest2, Default Domain Policy}
PS > Get-GPInheritance -target "OU=GroupA,OU=UserList,DC=furyu,DC=local" | % { $_.gpolinks }これで、 OUが "OU=GroupA,OU=UserList,DC=furyu,DC=local" のかかっているリンクのGPOをとりだすことができました。
GpoId : 09ecc96a-2d91-4594-8474-4404e82241d2
DisplayName : GPOtest1
Enabled : True
Enforced : False
Target : ou=groupa,ou=userlist,dc=furyu,dc=local
Order : 1
GpoId : 72e4f0a0-7b01-4944-9fba-6ad14faefb49
DisplayName : GPOtest2
Enabled : True
Enforced : False
Target : ou=groupa,ou=userlist,dc=furyu,dc=local
Order : 2
PS > Get-ADOrganizationalUnit -Filter 'Name -like "*"'これで全OUを取り出せるので、このオブジェクト群を変数にいれてしまいます。
City :
Country :
DistinguishedName : OU=Domain Controllers,DC=furyu,DC=local
LinkedGroupPolicyObjects : {CN={6AC1786C-016F-11D2-945F-00C04fB984F9},CN=Polici
es,CN=System,DC=furyu,DC=local}
ManagedBy :
Name : Domain Controllers
ObjectClass : organizationalUnit
ObjectGUID : ee6dfe99-a1f5-4579-b810-d12d22fcdfff
PostalCode :
State :
StreetAddress :
:
PS > $oulist=Get-ADOrganizationalUnit -Filter 'Name -like "*"'では、この変数を利用してリンクが貼られているOUとそのGPOを出してみましょう。
PS > $oulist | % { Get-GPInheritance -target $_ } | ? { $_.gpolinks -ne "" } | fl -Property path,gpolinks
Path : ou=domain controllers,dc=furyu,dc=local
GpoLinks : {Default Domain Controllers Policy}
Path : ou=groupa,ou=userlist,dc=furyu,dc=local
GpoLinks : {GPOtest1, GPOtest2}
Path : ou=groupb,ou=userlist,dc=furyu,dc=local
GpoLinks : {GPOtest2, GPOtest3, GPOtest1, GPOtest4}
. .\taskps.ps1
New-TaskFolder -folder (New-TaskObject) -path "\twitter"
Name Path
---- ----
twitter \twitter
Function Out-Twitter {じゃば、使ってみる。
BEGIN {
#check for global Twitter credential
if (!$global:Twitter_Credential) {
$global:Twitter_Credential=Get-Credential
}
}
PROCESS {
#turn off error pipeline
$erroractionpreference="SilentlyContinue"
[string]$tweet=$_
##Twitter投稿関数
function SubmitWebRequest(
[string] $RequestUrl,
[string] $RequestMethod,
[string] $RequestContentType,
[string] $PostString,
[string] $Username,
[string] $Password
)
{
[System.Net.ServicePointManager]::Expect100Continue = $false
$request = [System.Net.WebRequest]::Create($RequestUrl)
if ($Username) {
$request.Credentials = new-object System.Net.NetworkCredential($Username, $Password)
}
$request.Method = $RequestMethod
if ($RequestMethod -ieq "POST") {
$request.ContentType = $RequestContentType
$formdata = [System.Text.Encoding]::UTF8.GetBytes($PostString)
$request.ContentLength = $formdata.Length
$requestStream = $request.GetRequestStream()
$requestStream.Write($formdata, 0, $formdata.Length)
$requestStream.Close()
}
$response = $request.GetResponse()
$reader = new-object System.IO.StreamReader($response.GetResponseStream())
$returnvalue = $reader.ReadToEnd()
$reader.Close()
return $returnvalue
} #end function
#Short Url
Function Get-Snurl {
Param([string]$link="http://www.google.com")
$tinyurlrequest = "http://tinyurl.com/api-create.php?url=$link"
write-progress "Tweeting" "Getting tiny URL" -cu $tinyurlrequest
$tinyurl = SubmitWebRequest $tinyurlrequest "GET"
write-debug "Tweeting - Received tiny URL Response: $($tinyurl)"
write $tinyurl
}
#search for web links using Regex
[regex]$regex="(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?"
If ($tweet -match $regex) {
$link=$matches[0]
}
#if an embedded url was found, convert it to a snurl link
if ($link) {
$snurl=Get-Snurl $link
$tweet=$tweet.Replace($link,$snurl)
}
if ($tweet.Length -gt 140) {
Write-Warning ("Your message is " + (($tweet.length)-140) + " characters too long.")
$clear=$True
return
}
$tweetstring = [String]::Format("status={0}", $tweet)
$request = [Net.WebRequest]::Create($url)
$twitusername=$global:Twitter_Credential.GetNetworkCredential().Username
$twitpassword=$global:Twitter_Credential.GetNetworkCredential().Password
$twitResponseText = SubmitWebRequest `
"http://twitter.com/statuses/update.xml" `
"POST" `
"application/x-www-form-urlencoded" `
$tweetstring `
$twitusername `
$twitpassword
write-debug "Tweeting - Posted status update. Response: $($twitResponseText)"
}
END {
#if there was an error, then don't keep the global Twitter
#credential
if ($clear) {
Remove-Variable Twitter_Credential -scope Global
}
}
} #end Function
PS 2010/03/28 12:23> . .\fixtwit.ps1fixtwit.ps1 をドット化して実行。
PS 2010/03/28 12:24> "もう昼・・お腹すいた・・" | Out-Twitter
@echo offこれをバッチとして用意して実行すれば、
:1
echo HotFixチェック
set /p kbmonth=何ヶ月分のFotFixを出力しますか?:
powershell -command "& { Get-HotFix | ? { $_.InstalledOn -ge $(get-date).addmonths(-%kbmonth%) } }"
pause
goto 1
HotFixチェック
何ヶ月分のFotFixを出力しますか?:1
Source Description HotFixID InstalledBy InstalledOn
------ ----------- -------- ----------- -----------
BUSO-PC Update KB976264 NT AUTHORITY\SYSTEM 2010/03/10...
BUSO-PC Update KB980302 NT AUTHORITY\SYSTEM 2010/03/23...
続行するには何かキーを押してください . . .
HotFixチェック
何ヶ月分のFotFixを出力しますか?:2
Source Description HotFixID InstalledBy InstalledOn
------ ----------- -------- ----------- -----------
BUSO-PC Security Update KB971468 NT AUTHORITY\SYSTEM 2010/02/10...
BUSO-PC Security Update KB975560 NT AUTHORITY\SYSTEM 2010/02/10...
BUSO-PC Update KB976264 NT AUTHORITY\SYSTEM 2010/03/10...
BUSO-PC Update KB976662 NT AUTHORITY\SYSTEM 2010/02/24...
BUSO-PC Update KB976972 NT AUTHORITY\SYSTEM 2010/01/27...
:(略