【LDAPS】シェルスクリプトでActive Directoryユーザーのパスワードを安全に変更する方法

# はじめに
お疲れ様です。矢儀 @yuki_ink です。

```
なんかもう、Windows卒業したいな、、
けどドメインユーザもらってるしな、、
ドメインユーザのパスワード変更とか、Linuxから簡単にできないかな、、
```

Linuxから簡単に、ドメインユーザのパスワードを変更したい！！
ということで張り切っていきましょう。

# やったこと

以下の記事でご紹介した手順でLDAPS接続のための環境構築が完了していることを前提とさせていただきます。

https://qiita.com/yuki_ink/items/c5bcc22707d298881aa1

今回新しく実施するのは以下の操作です。

[1. リソースを作る](https://qiita.com/yuki_ink/items/4e303c6451f0ae2f607a#1-%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%92%E4%BD%9C%E3%82%8B)
[2. シェルスクリプト実行用サーバのセットアップ](https://qiita.com/yuki_ink/items/4e303c6451f0ae2f607a#2-%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)
    - [2.1. openldap-clients インストール](https://qiita.com/yuki_ink/items/4e303c6451f0ae2f607a#21-openldap-clients-%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)
    - [2.2 Microsoft ADにLDAPS通信する](https://qiita.com/yuki_ink/items/4e303c6451f0ae2f607a#22-microsoft-ad%E3%81%ABldaps%E9%80%9A%E4%BF%A1%E3%81%99%E3%82%8B)
[3. シェルスクリプトを作成する](https://qiita.com/yuki_ink/items/4e303c6451f0ae2f607a#3-%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)


# 1. リソースを作る
VPC・サブネットから、AWS Managed Microsoft AD・EC2まで、必要なリソースをすべて作成するCloudFormationテンプレートを用意しまた。
今回はこれを使ってリソースの作成を行います。

:::note
[前回](https://qiita.com/yuki_ink/items/c5bcc22707d298881aa1)からの差分はLinux Serverが追加になっているところだけです。
前回記事を参考にCloudFormationスタックを作成された場合、変更セットで差分を反映してください。
:::

<details><summary>CloudFormationテンプレート</summary>

:::note
事前にキーペアを作成していることを前提にしています。
パラメータ `KeyName` でキーペア名を指定してください。
:::

:::note
Windows ServerのAMIは、今回は「Windows_Server-2019-English-Full-Base-2024.11.13」を利用しました。
東京リージョンでは `ami-032985d75659a9d00` です。

Linux ServerのAMIは、「RHEL-8.4.0_HVM-20230419-x86_64-41-Hourly2-GP2」を利用しました。
東京リージョンでは `ami-0d99111f48bcb5564` です。
:::

:::note warn
今回は検証のため、EC2はパブリックサブネットに配置し、インターネット経由で接続します。
パラメータ `AllowedPublicIP` で指定したIPレンジからのRDP/SSHを許可するようにしていますが、扱いにはご注意ください。
:::

```vpc-msad-ec2-setup.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation template to create VPC, subnets with AZ selection, AWS Managed MSAD, and EC2 instances using Key Pair authentication.

Parameters:
  VpcCidr:
    Type: String
    Default: 10.0.0.0/16
    Description: CIDR block for the VPC
  Subnet1Cidr:
    Type: String
    Default: 10.0.1.0/24
    Description: CIDR block for AWS Managed MSAD subnet 1
  Subnet1Az:
    Type: String
    Default: us-east-1a
    Description: Availability Zone for AWS Managed MSAD subnet 1
  Subnet2Cidr:
    Type: String
    Default: 10.0.2.0/24
    Description: CIDR block for AWS Managed MSAD subnet 2
  Subnet2Az:
    Type: String
    Default: us-east-1b
    Description: Availability Zone for AWS Managed MSAD subnet 2
  Subnet3Cidr:
    Type: String
    Default: 10.0.3.0/24
    Description: CIDR block for EC2 subnet
  Subnet3Az:
    Type: String
    Default: us-east-1c
    Description: Availability Zone for EC2 subnet
  WindowsServerAMI:
    Type: String
    Description: AMI ID for Windows Server
  LinuxAMI:
    Type: String
    Description: AMI ID for Linux Server
  InstanceType:
    Type: String
    Default: t3.medium
    Description: EC2 instance type
  DomainName:
    Type: String
    Description: Fully qualified domain name for Microsoft AD
  AdminPassword:
    Type: String
    Description: Admin password for Microsoft AD
    NoEcho: true
  KeyName:
    Type: String
    Description: Name of the EC2 Key Pair to use for SSH/RDP access
  AllowedPublicIP:
    Type: String
    Description: Allowed public IP address for RDP and SSH access (e.g., 203.0.113.0/32)

Resources:
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCidr
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: MyVPC

  DHCPOptions:
    Type: AWS::EC2::DHCPOptions
    Properties:
      DomainName: !Sub '${DomainName}'
      DomainNameServers: !GetAtt MyMicrosoftAd.DnsIpAddresses

  VPCDHCPOptionsAssociation:
    Type: AWS::EC2::VPCDHCPOptionsAssociation
    Properties:
      VpcId: !Ref MyVPC
      DhcpOptionsId: !Ref DHCPOptions

  Subnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: !Ref Subnet1Cidr
      AvailabilityZone: !Ref Subnet1Az
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: MSAD-Subnet1

  Subnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: !Ref Subnet2Cidr
      AvailabilityZone: !Ref Subnet2Az
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: MSAD-Subnet2

  Subnet3:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: !Ref Subnet3Cidr
      AvailabilityZone: !Ref Subnet3Az
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: EC2-Subnet

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: MyInternetGateway

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref MyVPC
      InternetGatewayId: !Ref InternetGateway

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref MyVPC
      Tags:
        - Key: Name
          Value: PublicRouteTable

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Subnet3
      RouteTableId: !Ref PublicRouteTable

  VPCAllowAllSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow specific IP for RDP and SSH, and VPC internal communication
      VpcId: !Ref MyVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3389
          ToPort: 3389
          CidrIp: !Ref AllowedPublicIP
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref AllowedPublicIP
        - IpProtocol: -1
          CidrIp: !Ref VpcCidr
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: VPCAllowAllSG

  MyMicrosoftAd:
    Type: AWS::DirectoryService::MicrosoftAD
    Properties: 
      CreateAlias: false
      Edition: Standard
      EnableSso: false
      Name: !Ref DomainName
      Password: !Ref AdminPassword
      VpcSettings: 
        SubnetIds: 
          - !Ref Subnet1
          - !Ref Subnet2
        VpcId: !Ref MyVPC

  WindowsInstanceForADManagement:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !Ref WindowsServerAMI
      SubnetId: !Ref Subnet3
      KeyName: !Ref KeyName
      SecurityGroupIds:
        - !Ref VPCAllowAllSG
      Tags:
        - Key: Name
          Value: AD-Management-Server
      UserData:
        Fn::Base64: !Sub |
          <powershell>
          tzutil /s "Tokyo Standard Time"
          reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation" /v RealTimeIsUniversal /d 1 /t REG_DWORD /f
          Rename-Computer -NewName "ADManagementServer" -Force -Restart
          </powershell>

  WindowsInstanceForEnterpriseCA:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !Ref WindowsServerAMI
      SubnetId: !Ref Subnet3
      KeyName: !Ref KeyName
      SecurityGroupIds:
        - !Ref VPCAllowAllSG
      Tags:
        - Key: Name
          Value: Enterprise-CA-Server
      UserData:
        Fn::Base64: !Sub |
          <powershell>
          tzutil /s "Tokyo Standard Time"
          reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation" /v RealTimeIsUniversal /d 1 /t REG_DWORD /f
          Rename-Computer -NewName "EnterpriseCAServer" -Force -Restart
          </powershell>

  LinuxInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !Ref LinuxAMI
      SubnetId: !Ref Subnet3
      KeyName: !Ref KeyName
      SecurityGroupIds:
        - !Ref VPCAllowAllSG
      Tags:
        - Key: Name
          Value: LinuxServer
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          timedatectl set-timezone Asia/Tokyo
          hostnamectl set-hostname LinuxServer

Outputs:
  VPCId:
    Description: The ID of the created VPC
    Value: !Ref MyVPC
  ADManagementInstance:
    Description: Windows Server for AD Management
    Value: !Ref WindowsInstanceForADManagement
  EnterpriseCAInstance:
    Description: Windows Server for Enterprise CA
    Value: !Ref WindowsInstanceForEnterpriseCA
  LinuxInstance:
    Description: Linux Server instance ID
    Value: !Ref LinuxInstance
  DirectoryId:
    Description: The ID of the created Microsoft AD
    Value: !Ref MyMicrosoftAd
```

</details>

前回に引き続き、ドメインは `yagitest.local`。
DNSアドレスは `10.0.1.206` と `10.0.2.121` です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/f46f24d9-01e1-6a72-d7ec-65c96c026516.png)

EC2は以下の3台構成になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/b95e40dc-462d-7528-22a3-c70247d7f9b6.png)



# 2. シェルスクリプト実行用サーバのセットアップ

先ほど作成したLinux Serverでの作業になります。
ec2-userでログインしたところから想定して手順を書きます。

## 2.1. openldap-clients インストール

```
# openldap-clientsのインストール
sudo dnf install -y openldap-clients

# インストール確認
ldapsearch -VV
## バージョン情報が表示されれば、インストールは成功

# Microsoft ADへのLDAP接続テスト
ldapsearch -D "yagitest\Admin" -W -H ldap://yagitest.local -b "OU=Users,OU=yagitest,DC=yagitest,DC=local"
## コマンド打鍵後パスワード入力を求められる
## コマンドが正常に通ると、ドメインユーザの詳細一覧が表示される
```

<details><summary>実際にコマンドを打った時の結果がこちら。</summary>

```
[ec2-user@LinuxServer ~]$ sudo dnf install -y openldap-clients
Updating Subscription Management repositories.
Unable to read consumer identity

This system is not registered with an entitlement server. You can use subscription-manager to register.

Red Hat Enterprise Linux 8 for x86_64 - BaseOS   60 kB/s | 4.1 kB     00:00
Red Hat Ansible Engine 2 for RHEL 8 (RPMs) from  76 kB/s | 4.0 kB     00:00
RHUI Client Configuration Server 8               30 kB/s | 1.5 kB     00:00
Last metadata expiration check: 0:00:01 ago on Mon 09 Dec 2024 09:18:33 PM JST.
Dependencies resolved.
================================================================================
 Package            Arch     Version            Repository                 Size
================================================================================
Installing:
 openldap-clients   x86_64   2.4.46-20.el8_10   rhel-8-baseos-rhui-rpms   203 k

Transaction Summary
================================================================================
Install  1 Package

Total download size: 203 k
Installed size: 611 k
Downloading Packages:
openldap-clients-2.4.46-20.el8_10.x86_64.rpm    5.2 MB/s | 203 kB     00:00
--------------------------------------------------------------------------------
Total                                           3.1 MB/s | 203 kB     00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1
  Installing       : openldap-clients-2.4.46-20.el8_10.x86_64               1/1
  Running scriptlet: openldap-clients-2.4.46-20.el8_10.x86_64               1/1
  Verifying        : openldap-clients-2.4.46-20.el8_10.x86_64               1/1
Installed products updated.

Installed:
  openldap-clients-2.4.46-20.el8_10.x86_64

Complete!
[ec2-user@LinuxServer ~]$
[ec2-user@LinuxServer ~]$
[ec2-user@LinuxServer ~]$ ldapsearch -VV
ldapsearch: @(#) $OpenLDAP: ldapsearch 2.4.46 (Oct 15 2024 19:33:32) $
        mockbuild@x86-vm-07.brew-001.prod.iad2.dc.redhat.com:/builddir/build/BUILD/openldap-2.4.46/openldap-2.4.46/clients/tools
        (LDAP library: OpenLDAP 20446)
[ec2-user@LinuxServer ~]$
[ec2-user@LinuxServer ~]$
[ec2-user@LinuxServer ~]$ ldapsearch -D "yagitest\Admin" -W -H ldap://IP-C61301AD.yagitest.local -b "OU=Users,OU=yagitest,DC=yagitest,DC=local"
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <OU=Users,OU=yagitest,DC=yagitest,DC=local> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# Users, yagitest, yagitest.local
dn: OU=Users,OU=yagitest,DC=yagitest,DC=local
objectClass: top
objectClass: organizationalUnit
ou: Users
distinguishedName: OU=Users,OU=yagitest,DC=yagitest,DC=local
instanceType: 4
whenCreated: 20241207034246.0Z
whenChanged: 20241207034247.0Z
uSNCreated: 12905
uSNChanged: 12913
name: Users
objectGUID:: NoEGx+oUs0i5r4o2i6kzOQ==
systemFlags: -1946157056
objectCategory: CN=Organizational-Unit,CN=Schema,CN=Configuration,DC=yagitest,
 DC=local
isCriticalSystemObject: TRUE
dSCorePropagationData: 20241210120041.0Z
dSCorePropagationData: 20241210120041.0Z
dSCorePropagationData: 20241210120041.0Z
dSCorePropagationData: 20241210120041.0Z
dSCorePropagationData: 16010101000000.0Z

# Admin, Users, yagitest, yagitest.local
dn: CN=Admin,OU=Users,OU=yagitest,DC=yagitest,DC=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: Admin
description: DO NOT DELETE:  Provided by AWS for administration of directory o
 bjects.  This account has FULL CONTROL over the root OU: 'OU=yagitest,DC=yagi
 test,DC=local' and group management rights to groups in AWS Delegated Groups
 OU
distinguishedName: CN=Admin,OU=Users,OU=yagitest,DC=yagitest,DC=local
instanceType: 4
whenCreated: 20241207034247.0Z
whenChanged: 20241207085945.0Z
displayName: Admin
uSNCreated: 12921
memberOf: CN=AWS Delegated Administrators,OU=AWS Delegated Groups,DC=yagitest,
 DC=local
uSNChanged: 14414
name: Admin
objectGUID:: 223HPtnwy0eurFXaBDmW7Q==
userAccountControl: 512
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 133780485499589075
lastLogoff: 0
lastLogon: 133783117379190388
pwdLastSet: 133780165673611235
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAZK+sZFfKWr8TOgOWWAQAAA==
accountExpires: 9223372036854775807
logonCount: 26
sAMAccountName: Admin
sAMAccountType: 805306368
userPrincipalName: admin@yagitest.local
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=yagitest,DC=local
dSCorePropagationData: 20241207034303.0Z
dSCorePropagationData: 20241207034302.0Z
dSCorePropagationData: 20241207034259.0Z
dSCorePropagationData: 20241207034259.0Z
dSCorePropagationData: 16010714223649.0Z
lastLogonTimestamp: 133780355851740912

# search result
search: 2
result: 0 Success

# numResponses: 3
# numEntries: 2

```

</details>


## 2.2 Microsoft ADにLDAPS通信する
まず、[前回](https://qiita.com/yuki_ink/items/c5bcc22707d298881aa1)エクスポートした証明書 `LDAP-root-CA.cer` をLinux Serverの `/tmp` に配置します。

```
[ec2-user@LinuxServer tmp]$ ls -l /tmp
-rw-r--r--. 1 ec2-user ec2-user   1286 Dec  8 12:47 LDAP-root-CA.cer
```

そこから、以下のコマンドを叩いていきます。

```
# 証明書を.pemファイルに変換
openssl x509 -in /tmp/LDAP-root-CA.cer -out /tmp/LDAP-root-CA.pem

# 証明書をLDAP クライアントの証明書ストアに配置
sudo cp /tmp/LDAP-root-CA.pem /etc/openldap/certs

# LDAP クライアントの設定に証明書のパスを記述
sudo vi /etc/openldap/ldap.conf
## 末尾に以下を追記して保存
# ======
# Specify the path to the TLS CA certificate
# Used by OpenLDAP to establish trusted TLS connections with the AD domain 'yagitest.local'
TLS_CACERT      /etc/openldap/certs/LDAP-root-CA.pem
# ======

# Microsoft ADへのLDAPS接続テスト（Adminで接続）
ldapsearch -D "yagitest\Admin" -W -H ldaps://yagitest.local -b "OU=Users,OU=yagitest,DC=yagitest,DC=local"
## コマンド打鍵後パスワード入力を求められる
## コマンドが正常に通ると、ドメインユーザの詳細一覧が表示される
```







# 3. シェルスクリプトを作成する

以下のようにシェルスクリプトを作成しました。


```ad_password_changer.sh
#!/bin/bash
if [ "$#" -ne 3 ]; then
  echo "Usage: $0 <username> <old_password> <new_password>"
  exit 1
fi

USERNAME="$1"
OLD_PASSWORD="$2"
NEW_PASSWORD="$3"

# LDAPサーバーの設定
SERVER_HOST="yagitest.local"

LDAP_SERVER="ldaps://$SERVER_HOST"
LDAP_BIND_DN="CN=$USERNAME,OU=Users,OU=yagitest,DC=yagitest,DC=local"
TMP_LDIF_FILE=$(mktemp)
trap 'rm -f "$TMP_LDIF_FILE"; exit $RESULT' EXIT  # スクリプト終了時に一時ファイルを削除し、適切な終了コードを返す

# 一時ファイルの作成に失敗した場合
if [ ! -f "$TMP_LDIF_FILE" ]; then
    echo "Error: Failed to create temporary file"
    RESULT=1
    exit 1
fi

cat <<EOF > "$TMP_LDIF_FILE"
dn: $LDAP_BIND_DN
changetype: modify
replace: unicodePwd
unicodePwd:: $(echo -n "\"$NEW_PASSWORD\"" | iconv -f UTF-8 -t UTF-16LE | base64)
EOF

# iconvコマンドが失敗した場合のエラーチェック
if [ $? -ne 0 ]; then
    echo "Error: Failed to encode password"
    RESULT=1
    exit 1
fi

# LDAPサーバーへの接続とパスワード変更を試行
ldapmodify -H "$LDAP_SERVER" -D "$LDAP_BIND_DN" -w "$OLD_PASSWORD" -f "$TMP_LDIF_FILE"
RESULT=$?

if [ $RESULT -eq 0 ]; then
    echo "Password changed successfully for $USERNAME on server $SERVER_HOST"
    exit 0
else
    echo "Failed to change password for $USERNAME on server $SERVER_HOST. Please check the logs."
    exit 1
fi
```

## 3.1. 使い方
まず、シェルスクリプト実行用サーバの適当なパスにシェルスクリプトを配置します。
私は `/opt/script/ad_password_changer.sh` としました。

その際、シェルスクリプト内の変数を環境に応じて修正してください。
```
# LDAPサーバーの設定
SERVER_HOST="yagitest.local"

~~略~~
LDAP_BIND_DN="CN=$USERNAME,OU=Users,OU=yagitest,DC=yagitest,DC=local"
```

実行時に指定する引数はこんな感じ。

- 第1引数：パスワードを変更する対象のユーザ名（ドメイン指定は不要）
- 第2引数：パスワード変更対象ユーザの現在のパスワード
- 第3引数：パスワード変更対象ユーザの新しいパスワード


## 3.2. 補足

- 万一のDNSエラーでコケたくないので、IPアドレスでも接続できるようにしました。
- パスワードの設定をいじるためにはLDAPS接続（`ldaps://$SERVER_HOST`）が必須のようです。
※`ldap://$SERVER_HOST` にするとエラーになりました。



# やってみる

Adminのパスワード変更をしてみます。
```
[ec2-user@LinuxServer ~]$ /opt/script/ad_password_changer.sh Admin '<現在のパスワード>' '<新しいパスワード>'
Using hostname: IP-C61301AD.yagitest.local
modifying entry "CN=Admin,OU=Users,OU=yagitest,DC=yagitest,DC=local"

Password changed successfully for Admin on server IP-C61301AD.yagitest.local
```

うまくいきました！

:::note
AD管理用サーバへAdminでRDPしてみて、変更後のパスワードでログインできることを確認しておきましょう。
:::

ちなみに、誤ったパスワードを打ち込むとこうなります。
```
[ec2-user@LinuxServer ~]$ /opt/script/ad_password_changer.sh Admin '<誤ったパスワード>' '<新しいパスワード>'
Using hostname: IP-C61301AD.yagitest.local
ldap_bind: Invalid credentials (49)
        additional info: 80090308: LdapErr: DSID-0C09050F, comment: AcceptSecurityContext error, data 52e, v4563
Failed to change password for Admin on server IP-C61301AD.yagitest.local. Please check the logs.
```
`Invalid credentials` と教えてくれましたね。

ちなみにちなみに、新しいパスワードとして、パスワードポリシーを満たさない文字列（`123` など）を入れるとこうなりました。
```
[ec2-user@LinuxServer ~]$ /opt/script/ad_password_changer.sh Admin '<現在のパスワード>' '<パスワードポリシーを満たさないパスワード>'
Using hostname: IP-C61301AD.yagitest.local
modifying entry "CN=Admin,OU=Users,OU=yagitest,DC=yagitest,DC=local"
ldap_modify: Server is unwilling to perform (53)
        additional info: 0000052D: SvcErr: DSID-031A124C, problem 5003 (WILL_NOT_PERFORM), data 0


Failed to change password for Admin on server IP-C61301AD.yagitest.local. Please check the logs.
```
`Server is unwilling to perform` とのことで、パスワード変更が失敗します。


:::note warn
ユーザのパスワード期限が切れて↓のような状態になっていたら、このスクリプトによるパスワード変更はできませんでした。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/5205e157-f14a-745c-6990-9ae6c1887993.png)

:::



# 終わりに

ドメインユーザのパスワードを、LDAPSを用いたシェルスクリプトを用いて変更してみました。
これが何の役に立つのか分からないですが、どなたかの役に立てば幸いです




# 参考文献


https://qiita.com/bashaway/items/14f7ba6fda4dbcd7d15b

https://itc-engineering-blog.netlify.app/blogs/ldapadd-ad-ldaps

https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-troubleshoot-pem&locale=ja